Cómo obtener un contexto de sincronización para la segunda forma mostrada
-
12-10-2019 - |
Pregunta
[EDIT] reformulado y toda simplificado poste [/ EDIT]
En este el blog , la siguiente (I simplifica un poco) se da como un ejemplo del uso de un objeto SynchronizationContext para ejecutar una tarea en el subproceso de interfaz de usuario:
Task.Factory.StartNew(() =>"Hello World").ContinueWith(
task => textBox1.Text = task.Result,
TaskScheduler.FromCurrentSynchronizationContext());
Me puede repetir estos resultados en un nuevo proyecto, la actualización de la interfaz de usuario de forma segura, pero por alguna razón en mi proyecto actual (aunque es estado de trabajo) no puedo. Me da la norma "Usted no tiene permiso para actualizar la interfaz de usuario del hilo equivocado" excepción.
Mi código (en MainForm_Load (...)) es así, que trabaja en un nuevo proyecto w / a textBox1 añadida a la forma principal, pero no funciona en mi proyecto actual:
var one = Task.Factory.StartNew(
() => "Hello, my name is Inigo Montoya");
var two = one.ContinueWith(
task => textBox1.Text = one.Result,
TaskScheduler.FromCurrentSynchronizationContext());
Alguien tiene alguna idea de lo que podría ser el gong.
[EDIT]
he rastreado la parte posterior de error a la ejecución de un objeto que utiliza un formulario para solicitar al usuario información de acceso. El error sólo ocurre cuando la forma se ha demostrado. (Si vuelvo un valor codificado antes de que Show
del Formulario pasa toda la cosa funciona bien).
Nueva pregunta: ¿Cómo puedo obtener el SynchronizationContext de la forma que estoy construyendo, si sus propias pantallas constructor otra forma antes de que se ha demostrado? He aquí cómo usted puede reproducir lo que está sucediendo:
1) Crear dos formas: Form1 con un TextBox
, y Form2 con un Button
2) Crear un OwnedBy1Uses2
clase
Form1
:
public partial class Form1 : Form
{
OwnedBy1Uses2 member;
public Form1()
{
InitializeComponent();
member = new OwnedBy1Uses2();
}
private void Form1_Load(object sender, EventArgs e)
{
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task<string> getData = Task.Factory.StartNew(
() => "My name is Inigo Montoya...");
Task displayData = getData.ContinueWith(
t => textBox1.Text = t.Result, ui);
}
}
Form2
:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
DialogResult = System.Windows.Forms.DialogResult.Cancel;
}
private void button1_Click(object sender, EventArgs e)
{
DialogResult = System.Windows.Forms.DialogResult.OK;
Hide();
}
}
OwnedBy1Uses2
:
class OwnedBy1Uses2
{
int x;
public OwnedBy1Uses2()
{
using (Form2 form = new Form2())
{
if (form.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
x = 1;
}
else
{
x = 2;
}
}
}
}
Solución
Sólo estar en el hilo principal no es suficiente. Es necesario tener un SynchronizationContext.Current
válida (establecer un punto de interrupción en la línea FromCurrentSynchronizationContext
y examinar el valor de SynchronizationContext.Current
; si se trata de null
, entonces mal de algo).
La solución más limpia es para ejecutar el código de tarea, incluyendo FromCurrentSynchronizationContext
desde dentro del bucle de mensajes de interfaz de usuario -., Es decir, de algo así como Form.Load
para Windows Forms o WPF para Window.Loaded
Editar
Se produjo un error en Windows Forms, donde ponerla En Form.Load
no fue suficiente, ya sea - que en realidad tenía que forzar la creación de mango Win32 leyendo la propiedad Handle
. Yo tenía la impresión de que este error se había fijado, pero podría estar equivocado.
Editar 2 (copiado de comentario):
Sospecho que su problema es que usted está llamando fuera de ShowDialog
Application.Run
. ShowDialog
es un bucle de mensajes anidados, pero en este caso no hay ningún bucle de mensajes de los padres. Si se establece una vigilancia sobre SynchronizationContext.Current
y el paso a través de la ShowDialog
, verá que se trata de un WindowsFormsSynchronizationContext
antes de que se muestre el diálogo, pero cambia a un SynchronizationContext
no WinForms después de que el diálogo se muestra. Mover la creación miembro (incluyendo el ShowDialog
) de las correcciones de eventos Load
el problema.