Buenas ya se que esta pregunta es genérica y básica pero yo quiero centrarme en la eficiencia y cual es más fácil de entender cuando se relee el código.
en este link podeis encontrar las diferencias:
http://www.elguille.info/NET/vs2005/trucos/acceder_a_un_control_desde_otro_hilo.htm (http://www.elguille.info/NET/vs2005/trucos/acceder_a_un_control_desde_otro_hilo.htm)
mi cuestión es que he descubierto otra forma y me gustaría una opinion a ver cual les parece más clara y si sabrían decirme a nivel de eficiencia cual es la mejor.
mi forma
string mensaje = "";
if(InvokeRequired)
{
Invoke(new Action(() => mensaje += combobox.SelectedItem));
}
como se ve en este caso se utiliza una función lamba.
¿A que diferencia te refieres exactamente?.
En ambos códigos el tuyo y el de aquella url se llama al mismo método 'Windows.Forms.Control.InvokeRequired' y 'Windows.Forms.Control.Invoke', le pasas el delegado y al compilar se generan las mismas instrucciones IL que internamente determinan lo mismo, hallar el handle del control/form para descubrir a que thread pertenece.
No hay diferencia alguna en lo que se refiere a eficiencia, tampoco por que le pases un delegado con la referencia del método o una expresión lambda.
Ahora, deberías seguir los ejemplos de buenos hábitos, es decir, invocar el control y no el form (aunque eso no afecta para nada al rendimiento pero puede resultar en confusión), y ademas añadir una verificación antes de invocarlo:
Ejemplo en VB.Net
Dim msg As String = "" & ComboBox1.SelectedItem() ' No es necesario invocar para leer.
Select Case Me.TextBox1.InvokeRequired
Case True ' Invoco para modificar la propiedad.
Me.TextBox1.Invoke(Sub() Me.TextBox1.Text = msg)
Case Else
Me.TextBox1.Text = msg
End Select
Traducción online a C#:
string msg = "" + ComboBox1.SelectedItem(); // No es necesario invocar para leer.
switch (this.TextBox1.InvokeRequired) {
case true: // Invoco para modificar la propiedad.
this.TextBox1.Invoke(() => this.TextBox1.Text == msg);
break;
default:
this.TextBox1.Text = msg;
break;
}
Si quieres reducir el código para no tener que estar escribiendo siempre lo mismo, puedes desarrollar un método genérico cómo este:
''' <remarks>
''' *****************************************************************
''' Snippet Title: Control Invoker
''' Code's Author: Elektro
''' Date Modified: 03-April-2015
''' Usage Example:
''' ControlInvoker(TextBox1, Sub(tb) tb.Text = "Hello World!")
'''
''' ControlInvoker(TextBox1, Sub(tb As TextBox)
''' For x As Integer = 0 To 5
''' tb.AppendText(CStr(x))
''' Next x
''' End Sub)
''' *****************************************************************
''' </remarks>
''' <summary>
''' Executes an encapsulated method on the thread that owns the specified control.
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="ctrl">The control to invoke.</param>
''' <param name="method">The encapsulated method to be called.</param>
Public Sub ControlInvoker(Of T As Control)(ByVal ctrl As T, ByVal method As Action(Of T))
If ctrl.InvokeRequired Then
ctrl.Invoke(New Action(Of T, Action(Of T))(AddressOf ControlInvoker), ctrl, method)
Else
method(ctrl)
End If
End Sub
Traducción online a C#:
/// <remarks>
/// *****************************************************************
/// Snippet Title: Control Invoker
/// Code's Author: Elektro
/// Date Modified: 03-April-2015
/// Usage Example:
/// ControlInvoker(TextBox1, Sub(tb) tb.Text = "Hello World!")
///
/// ControlInvoker(TextBox1, Sub(tb As TextBox)
/// For x As Integer = 0 To 5
/// tb.AppendText(CStr(x))
/// Next x
/// End Sub)
/// *****************************************************************
/// </remarks>
/// <summary>
/// Executes an encapsulated method on the thread that owns the specified control.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ctrl">The control to invoke.</param>
/// <param name="method">The encapsulated method to be called.</param>
public void ControlInvoker<T>(T ctrl, Action<T> method) where T : Control
{
if (ctrl.InvokeRequired) {
ctrl.Invoke(new Action<T, Action<T>>(ControlInvoker), ctrl, method);
} else {
method(ctrl);
}
}
Ejemplos de uso en VB.Net
ControlInvoker(TextBox1, Sub(tb) tb.Text = "Hello World!")
ControlInvoker(TextBox1, Sub(tb As TextBox)
For x As Integer = 0 To 5
tb.AppendText(CStr(x))
Next x
End Sub)
Traducción online a C#:
ControlInvoker(TextBox1, tb => tb.Text == "Hello World!");
ControlInvoker(TextBox1, (TextBox tb) =>
{
for (int x = 0; x <= 5; x++) {
tb.AppendText(Convert.ToString(x));
}
})
Saludos.
Hola,
muchísimas gracias por tu respuesta, si no entiendo mal la clase Invokerequired e Invoke es lo mismo. Mi pregunta ahora es: El hecho de usar delegados para esta tarea facilita la compresensión del código? Es decir, de los dos métodos el de la página y el mío ¿Cual te costaría menos entender?
saludos.
Cita de: kondrag_X1 en 5 Abril 2015, 17:09 PMsi no entiendo mal la clase Invokerequired e Invoke es lo mismo.
Para nada, quizás me interpretaste mal, la propiedad
InvokeRequired simplemente determina si es necesario llamar al método Invoke (éste comprueba si el control se encuentra en un hilo diferente al actual), y el método
Invoke hace el resto, realiza la invocación.
Si invocas repetidamente el control desde el hilo que lo creó sin realizar el chequeo con InvokeRequired entonces producirá una (muy ínfima) disminuición de rendimiento.
Si estás seguro de que el control siempre va a ser invocado desde un hilo distinto al que lo creó entones no es necesario realizar el chequeo con InvokeRequired pero tampoco está de más conservar los buenos hábitos añadiendo el chequeo.
Cita de: kondrag_X1 en 5 Abril 2015, 17:09 PMMi pregunta ahora es: El hecho de usar delegados para esta tarea facilita la compresensión del código? Es decir, de los dos métodos el de la página y el mío ¿Cual te costaría menos entender?
Hombre... creo que la comprensión del código depende de las circunstancias y de los gustos de cada uno.
Pongo cómo ejemplo este código:
sub()
Me.TextBox1.Invoke(Sub() Me.TextBox1.Text = msg)
end sub
En mi opinión no es muy correcto tener un método encapsulado en otro método, pero usar una expresión lamdba ahí a mi me resulta más comprensible que crear el delegado y defnir un método adicional en otra parte del código, por que solamente estoy modificando una propiedad en ese ejemplo y además se que no hay lugar a ninguna posible excepción cross-thread o de otro tipo.
Al invocar, yo utilizaría los delegados para reemplazar a una expresión lambda en caso de que tuviese que realizar varias operaciones o en caso de que no estuviese del todo seguro de si pueden producirse excepciones entonces las controlaría en el método del delegado en lugar de en el bloque del lambda por que demasiadas isntrucciones quedaría bastante feo y además el lambda es un método anónimo.
Saludos!