c# - traves - realizar llamadas seguras para subprocesos en controles de formularios windows forms
La forma más corta de escribir un método de acceso seguro para subprocesos a un control de formularios de Windows (5)
1) Usando delegado anónimo
private void SetText(string text)
{
if (this.InvokeRequired)
{
Invoke(new MethodInvoker(delegate() {
SetText(text);
}));
}
else
{
this.textBox1.Text = text;
}
}
2) enfoque AOP
[RunInUIThread]
private void SetText(string text)
{
this.textBox1.Text = text;
}
http://weblogs.asp.net/rosherove/archive/2007/05.aspx?PageIndex=2
3) Usando expresiones lambda (delineadas por otros).
En este articulo:
El autor utiliza el siguiente método para realizar llamadas seguras para subprocesos a un control de Windows Forms:
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
¿Hay una manera más corta de lograr lo mismo?
Edit: debo mencionar que no consideraría esto como una mejor práctica
Si está utilizando 3.5 puede hacer un método de extensión al efecto de:
public static void SafeInvoke(this Control control, Action handler) {
if (control.InvokeRequired) {
control.Invoke(handler);
}
else {
handler();
}
}
esto es básicamente tomado de: Here
Entonces úsalo como:
textBox1.SafeInvoke(() => .... );
Por supuesto, modifique la extensión, etc. para sus usos.
Esto puede ser obvio para la mayoría, pero puede aceptar la respuesta aceptada y agregar otro método si necesita recuperar el valor ...
public static T SynchronizedFunc<T>(this ISynchronizeInvoke sync, Func<T> func)
{
if (!sync.InvokeRequired)
{
// Execute the function
return func();
}
// Marshal onto the context
return (T) sync.Invoke(func, new object[] { });
}
Utilicé esto recientemente para controlar el formulario de forma segura para subprocesos ...
var handle = f.SynchronizedFunc(() => f.Handle);
La solución más corta que he encontrado se muestra en el ejemplo de botón a continuación, donde el objetivo es cambiar el texto de un botón.
if (buttonX.InvokeRequired)
buttonX.Invoke((Action)(() => buttonX.Text = "Record"));
else
buttonX.Text = "Record";
C # 3.0 y después:
Un método de extensión generalmente sería el camino a seguir, ya que siempre querrá realizar una acción en una implementación de interfaz ISynchronizeInvoke
, es una buena opción de diseño.
También puede aprovechar los métodos anónimos (cierres) para tener en cuenta el hecho de que no sabe qué parámetros pasar al método de extensión; El cierre capturará el estado de todo lo necesario.
// Extension method.
static void SynchronizedInvoke(this ISynchronizeInvoke sync, Action action)
{
// If the invoke is not required, then invoke here and get out.
if (!sync.InvokeRequired)
{
// Execute action.
action();
// Get out.
return;
}
// Marshal to the required context.
sync.Invoke(action, new object[] { });
}
Entonces lo llamarías así:
private void SetText(string text)
{
textBox1.SynchronizedInvoke(() => textBox1.Text = text);
}
Aquí, el cierre es sobre el parámetro de text
, ese estado se captura y se pasa como parte del delegado de Action
pasa al método de extensión.
Antes de C # 3.0:
No tiene el lujo de las expresiones lambda, pero aún puede generalizar el código. Es casi lo mismo, pero no es un método de extensión:
static void SynchronizedInvoke(ISynchronizeInvoke sync, Action action)
{
// If the invoke is not required, then invoke here and get out.
if (!sync.InvokeRequired)
{
// Execute action.
action();
// Get out.
return;
}
// Marshal to the required context.
sync.Invoke(action, new object[] { });
}
Y luego lo llamas con sintaxis de método anónimo:
private void SetText(string text)
{
SynchronizedInvoke(textBox1, delegate() { textBox1.Text = text; });
}