Pregunta

Estoy escribiendo una aplicación WinForms que tiene dos modos:consola o GUI.Tres proyectos dentro de la misma solución, uno para la aplicación de consola, uno para los formularios de la interfaz de usuario y el tercero para mantener la lógica de que las dos interfaces también se conectarán.La aplicación de consola se ejecuta absolutamente sin problemas.

Un modelo que contiene las selecciones del usuario, tiene un IList<T> donde T es un objeto local, Step, que implementa INotifyPropertyChanged, por lo que en la interfaz de usuario esto está montado en un DataGridView.Todo está bien en tiempo de ejecución, el estado inicial de los objetos se refleja en la pantalla.

Cada una de las Step objetos es una tarea que se realiza por turnos;algunas de las propiedades cambiarán, se reflejarán en IList y se pasarán a DataGridView.

Esta acción en las versiones de la interfaz de usuario se realiza mediante la creación de un BackgroundWorker que genera eventos en la interfaz de usuario.El Step lo hace y genera un StepResult objeto que es un tipo enumerado que indica un resultado (p. ej.Ejecutando, NotRun, OK, NotOK, Advertencia) y una cadena para indicar un mensaje (porque el paso se ejecutó pero no como se esperaba, es decir.con una advertencia).Normalmente las acciones implicarán una interacción con la base de datos, pero en el modo de depuración genero un resultado aleatoriamente.

Si el mensaje es nulo, nunca hay problema, pero si genero una respuesta como esta:

StepResult returnvalue = new StepResult(stat, "completed with caveat")

Recibo un error que dice que se estaba accediendo a DataGridView desde un hilo distinto del hilo en el que se creó.(Estoy pasando esto a través de un controlador personalizado que debería manejar la invocación cuando sea necesario, ¿quizás no sea así?)

Entonces, si genero una respuesta única, p.usando un número aleatorio r:

StepResult returnvalue = new StepResult(stat, r.ToString());

las acciones se realizan sin problemas, los números se escriben limpiamente en DataGridView.

Estoy desconcertado.Supongo que es de alguna manera un problema de cadena literal, pero ¿alguien puede dar una explicación más clara?

¿Fue útil?

Solución

Dado que está haciendo un enlace de UI mediante suscripción de evento, puede resultarle útil ; Es un ejemplo que escribí hace un tiempo que muestra cómo subclasificar BindingList<T> para que las notificaciones se agrupen automáticamente en el hilo de la interfaz de usuario.

Si no hay contexto de sincronización (es decir, modo consola), vuelve a la invocación directa simple, por lo que no hay sobrecarga. Cuando se ejecuta en el subproceso de la interfaz de usuario, tenga en cuenta que esto esencialmente utiliza Control.Invoke, que solo ejecuta el delegado directamente si está en el subproceso de la interfaz de usuario. Por lo tanto, solo hay un cambio si los datos se están editando desde un subproceso que no es de la interfaz de usuario; se ajusta a lo que queremos ;-p

Otros consejos

Has respondido tu propia pregunta: -

  

Recibo un error que dice que se estaba accediendo a DataGridView desde un subproceso distinto del subproceso en el que se creó.

WinForms insiste en que todas las acciones realizadas en formularios y controles se realizan en el contexto del hilo en el que se creó el formulario. La razón de esto es compleja, pero tiene mucho que ver con la API Win32 subyacente. Para obtener más información, consulte las diversas entradas en el el blog The Old New Thing .

Lo que debe hacer es utilizar los métodos InvokeRequired e Invoke para garantizar que siempre se acceda a los controles desde el mismo hilo (pseudocódigo):

object Form.SomeFunction (args)
{
  if (InvokeRequired)
  {
    return Invoke (new delegate (Form.Somefunction), args);
  }
  else
  {
    return result_of_some_action;
  }
}

Tuve este mismo problema antes. Tal vez este artículo que publiqué sobre él pueda ayudar.

http: //cyberkruz.vox .com / library / post / net-problem-async-and-windows-forms.html

Encontré este artículo - "Actualizando IBindingList desde un hilo diferente" - que señaló con el dedo culpable a BindingList -

Debido a que BindingList no está configurado para operaciones asíncronas, debe actualizar BindingList desde el mismo subproceso en el que estaba controlado.

Pasar explícitamente el formulario principal como ISynchronizeInvoke objeto y creando un contenedor para el BindingList<T> Hizo el truco.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top