2008-11-19 25 views

Respuesta

10

Dispatcher es un componente de WPF, no un componente de WinForms.

Si desea enviar elementos de trabajo en el hilo de la interfaz de usuario, entonces deberá usar Control.BeginInvoke como ya ha encontrado, o reaccionar a ResetEvents/WaitObjects en los hilos.

Normalmente, invocar elementos de trabajo en el hilo de la interfaz de usuario es malo a menos que sea un trabajo de interfaz de usuario (es decir, actualizar el contenido de un control o algo), en cuyo caso sería suficiente Control.BeginInvoke().

+2

¿Eso es un sí o un no? ¿Y cómo funciona la interoperabilidad de WinForms en esto? –

1

Use hilo de fondo de trabajo como su mensaje de UI pump aware, This MSDN Article aunque sobre todo acerca de WPF indica que el BWT es consciente de la interfaz de usuario, incluso para formularios de Windows.

16

Puede usar Dispatcher incluso en una aplicación WinForms.

Si no está seguro de estar en un hilo de interfaz de usuario (por ejemplo en un controlador de button.Click), Dispatcher.CurrentDispatcher le da al despachador hilo de interfaz de usuario que se puede utilizar posteriormente para despachar a partir de hilos de fondo para el hilo de interfaz de usuario como de costumbre.

0

Eche un vistazo a backgrounder y vea si se ajusta a sus necesidades.

+0

A) la información básica es GPL. Por lo tanto, solo es útil para proyectos que también son GPL. B) Si usa .NET 4 o posterior, esta funcionalidad está integrada en la API. Consulte [System.Threading.Tasks.Task] (https://msdn.microsoft.com/en-us/library/system.threading.tasks.task (v = vs.100) .aspx). –

1

tuve un problema similar usando clase de dependencia de Oracle que se ejecuta en su propio hilo dentro de Windows Forms,

Cuando AlCambiar evento disparado desde Oracle Dependencia, que ha querido mostrar los cambios en el DataGridView, simplemente definiendo DataSource para eventargs.Details (que es esencialmente una DataTable), y arroja: System.InvalidOperationException no fue manejado por el código de usuario Mensaje = operación Cross-thread no válida: Controle 'dataGridView1' accedido desde un hilo que no sea el hilo en el que fue creado.

Stackoverflow usuario Brian Peiris ([email protected]), colega mío me mostró este revés:

void dep_OnChange(object sender, OracleNotificationEventArgs arg) 
     { 
     Console.WriteLine("Notification received"); 

     int infoSum = int.Parse(arg.Details.Compute("Sum(Info)", "Info is not null").ToString()); 
     InfoSum x = (InfoSum)infoSum; 
     foreach (DataRow dr in arg.Details.Rows) 
      { 
      Console.WriteLine(string.Format("Operation(InfoSum)= {0}", Enum.GetName(typeof(InfoSum), x))); 
      Console.WriteLine(string.Format("ontable={0} Rowid={1},info={2}", dr.Field<string>("ResourceName"), dr.Field<string>("rowid"), dr.Field<Int32>("info"))); 
      } 
     // Following will throw cross-thread 
     // dataGridView1.DataSource = arg.Details; 
     // instead of line above use the following 
     dataGridView1.BeginInvoke((Action)(()=>dataGridView1.DataSource = arg.Details)); 
     IsNotified = true; 
     } 

     } 
9

he proporcionado un ejemplo del uso System.Windows.Threading.Dispatcher en Windows Form in my answer to question "Programación paralela utilizando el TPL Windows Forms", ya que the previous answer to your question:

Si no está seguro de estar en hilo de interfaz de usuario (. por ejemplo, en un controlador button.Click), Dispatcher.CurrentDispatcher le da al despachador hilo de interfaz de usuario que puede utilizar para enviar desde el hilo de fondo al hilo de la interfaz de usuario como de costumbre.

es o engañosa o confusa o carece de la contexto de uso concreto:

  • button.Click controlador no asegura estar en hilo de interfaz de usuario;
  • si no está en hilo de interfaz de usuario, sigue siendo posible utilizar el disparcher de hilo de interfaz de usuario del formulario Windows Forms

Uno puede conseguir despachador de hilo WinForm interfaz de usuario:

Dispatcher dispatcherUI = Dispatcher.CurrentDispatcher; 

en cualquiera de los botones haga clic en controlador de eventos o en cualquier otro lugar (en forma de constructor)

y luego usarlo para ejecutar en la interfaz de usuario de otros temas, ver más detalles de ejemplo a continuación en my answer:

private void button1_Click(object sender, EventArgs e) 
{ 
    Dispatcher dispUI = Dispatcher.CurrentDispatcher; 
    for (int i = 2; i < 20; i++) 
    { 
    int j = i; 
    var t = Task.Factory.StartNew 
      (() => 
     { 
     var result = SumRootN(j); 
     dispUI.BeginInvoke 
      (new Action 
       (() => richTextBox1.Text += "root " + j.ToString() 
         + " " + result.ToString() + Environment.NewLine 
       ) 
      , null 
      ); 
     } 
      ); 
} 
+2

'using System.Threading;' _ "Tipo o espacio de nombres" Dispatcher "No se pudo encontrar ...." _ – n00dles

0

A veces, un componente del temporizador es útil y fácil de configurar en WinForms, simplemente establezca su intervalo y luego habilítelo, luego asegúrese de que lo primero que hace en su controlador de eventos Tick es deshabilitarse.

Creo que Timer ejecuta el código en su propio hilo, por lo que puede necesitar hacer un BeginInvoke (llamado al objeto WinForm [this]) para ejecutar su Acción.

private WebBrowserDocumentCompletedEventHandler handler; //need to make it a class field for the handler below (anonymous delegates seem to capture state at point of definition, so they can't capture their own reference) 
private string imageFilename; 
private bool exit; 

public void CaptureScreenshot(Uri address = null, string imageFilename = null, int msecDelay = 0, bool exit = false) 
{ 
    handler = (s, e) => 
    { 
    webBrowser.DocumentCompleted -= handler; //must do first 

    this.imageFilename = imageFilename; 
    this.exit = exit; 

    timerScreenshot.Interval = (msecDelay > 0)? msecDelay : 1; 
    timerScreenshot.Enabled = true; 
    }; 

    webBrowser.DocumentCompleted += handler; 
    Go(address); //if address == null, will use URL from UI 
} 

private void timerScreenshot_Tick(object sender, EventArgs e) 
{ 
    timerScreenshot.Enabled = false; //must do first 

    BeginInvoke((Action)(() => //Invoke at UI thread 
    { //run in UI thread 

    BringToFront(); 
    Bitmap bitmap = webBrowser.GetScreenshot(); 

    if (imageFilename == null) 
     imageFilename = bitmap.ShowSaveFileDialog(); 

    if (imageFilename != null) 
    { 
     Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(imageFilename))); //create any parent directories needed 
     bitmap.Save(imageFilename); 
    } 

    bitmap.Dispose(); //release bitmap resources 

    if (exit) 
     Close(); //this should close the app, since this is the main form 

    }), null); 
} 

se puede ver por encima de la herramienta en acción en WebCapture (http://gallery.clipflair.net/WebCapture, código fuente en: http://ClipFlair.codeplex.com, ver carpeta Herramientas/WebCapture) que capte imágenes de los sitios web. Por cierto, si quieres llamar al ejecutable desde la línea de comandos asegúrate de ir a Propiedades del proyecto y en la pestaña Seguridad desactiva la seguridad ClickOnce (de lo contrario no puede acceder a la línea de comandos)