调用任何交叉线程代码的最佳方法?

CLa*_*RGe 36 .net c# invoke

我知道之前已经问过这个问题,但我正在寻找一种方法:

  1. 简化安全交叉线程代码的创建.
  2. 在任何情况下重用此代码(没有Windows窗体引用).

这是我到目前为止,但我想删除Windows窗体引用.有任何想法吗?

public delegate void SafeInvokeDelegate(System.Action action);
public class SafeInvoke
{
    private readonly System.Windows.Forms.Control _threadControl;

    public SafeInvoke()
    {
        _threadControl = new System.Windows.Forms.Control();
    }

    public void Invoke(System.Action action)
    {
        if (_threadControl.InvokeRequired)
            _threadControl.Invoke(new SafeInvokeDelegate(Invoke), new object[] {action});
        else if (action != null) action();
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的类可能会这样使用:

SafeInvoke _safeInvoker = new SafeInvoke();
void SafeClearItems()
{
    _safeInvoker.Invoke(delegate
        {
            listView1.Items.Clear();
        });
}
Run Code Online (Sandbox Code Playgroud)

我如何删除SafeInvoke类中的System.Windows.Forms.Control但保持相同的功能?

Sam*_*uel 91

您还可以使用扩展方法和lambdas来使代码更清晰.

using System.ComponentModel;
public static class ISynchronizeInvokeExtensions
{
  public static void InvokeEx<T>(this T @this, Action<T> action) where T : ISynchronizeInvoke
  {
    if (@this.InvokeRequired)
    {
      @this.Invoke(action, new object[] { @this });
    }
    else
    {
      action(@this);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

所以现在您可以InvokeEx在任何ISynchronizeInvoke上使用,并且能够访问实现类的属性和字段.

this.InvokeEx(f => f.listView1.Items.Clear());
Run Code Online (Sandbox Code Playgroud)

  • 为什么不简单地`listView1.InvokeEx(lv => lv.Items.Clear());`? (8认同)
  • 你先生是个天才,这个解决方案解决了我的问题,谢谢! (2认同)

Jon*_*eet 10

ISynchronizeInvoke而不是Control.这是Control实现的接口Invoke/BeginInvoke/EndInvoke/InvokeRequired.

另一种方法是使用SynchronizationContext.Current- BackgroundWorker我相信这是什么用途.


小智 7

如今,Invoke很容易.
例如,假设我们要调用Label(lblVal)来获取txtVal的值

lblVal.Invoke((MethodInvoker)delegate{lblVal.Text = txtVal.Text;});
Run Code Online (Sandbox Code Playgroud)

......就这么简单:D


Eya*_*yal 5

这是在 VB.net 中,与 Samuel 的答案非常相似。我有四个重载,具体取决于您是否想要子例程或函数以及是否有参数。为更多参数添加更多重载将很容易。VB.Net 能够推断类型。

Module ISynchronizeInvokeExtensions
    Public Delegate Function GenericLambdaFunctionWithParam(Of InputType, OutputType)(ByVal input As InputType) As OutputType
    Private Delegate Function InvokeLambdaFunctionCallback(Of InputType, OutputType)(ByVal f As GenericLambdaFunctionWithParam(Of InputType, OutputType), ByVal input As InputType, ByVal c As System.ComponentModel.ISynchronizeInvoke) As OutputType
    Public Function InvokeEx(Of InputType, OutputType)(ByVal f As GenericLambdaFunctionWithParam(Of InputType, OutputType), ByVal input As InputType, ByVal c As System.ComponentModel.ISynchronizeInvoke) As OutputType
        If c.InvokeRequired Then
            Dim d As New InvokeLambdaFunctionCallback(Of InputType, OutputType)(AddressOf InvokeEx)
            Return DirectCast(c.Invoke(d, New Object() {f, input, c}), OutputType)
        Else
            Return f(input)
        End If
    End Function

    Public Delegate Sub GenericLambdaSubWithParam(Of InputType)(ByVal input As InputType)
    Public Sub InvokeEx(Of InputType)(ByVal s As GenericLambdaSubWithParam(Of InputType), ByVal input As InputType, ByVal c As System.ComponentModel.ISynchronizeInvoke)
        InvokeEx(Of InputType, Object)(Function(i As InputType) As Object
                                           s(i)
                                           Return Nothing
                                       End Function, input, c)
    End Sub

    Public Delegate Sub GenericLambdaSub()
    Public Sub InvokeEx(ByVal s As GenericLambdaSub, ByVal c As System.ComponentModel.ISynchronizeInvoke)
        InvokeEx(Of Object, Object)(Function(i As Object) As Object
                                        s()
                                        Return Nothing
                                    End Function, Nothing, c)
    End Sub

    Public Delegate Function GenericLambdaFunction(Of OutputType)() As OutputType
    Public Function InvokeEx(Of OutputType)(ByVal f As GenericLambdaFunction(Of OutputType), ByVal c As System.ComponentModel.ISynchronizeInvoke) As OutputType
        Return InvokeEx(Of Object, OutputType)(Function(i As Object) f(), Nothing, c)
    End Function
End Module
Run Code Online (Sandbox Code Playgroud)

用法(在后台运行):

    InvokeEx(Sub(x As String) Me.Text = x, "foo", Me) 'set form title to foo
    InvokeEx(AddressOf MsgBox, Me.Text, Me)
    InvokeEx(Sub() Me.Text &= "!", "foo", Me) 'append "!" to form title
    InvokeEx(AddressOf MsgBox, Me.Text, Me)
    Dim s As String = InvokeEx(Function() Me.Text, Me) & "bar" 'get form title to backgorundworker thread
    InvokeEx(AddressOf MsgBox, s, Me) 'display the string from backgroundworker thread
Run Code Online (Sandbox Code Playgroud)