MethodInvoker + lambda + arguments + CrossThread Operation

时间:2011-04-24 13:09:10

标签: c# .net multithreading invoke

我正在使用它来改变其他线程上的内容:

        MethodInvoker m = () => { login_submit.Text = "Login"; };
        if (InvokeRequired)
        {
            BeginInvoke(m);
        }
        else
        {
            Invoke(m);
        }

这很好。

如何将争论传递给lamba表达式?

我想这样做:

        MethodInvoker m = (string txt) => { login_submit.Text = txt; };
        if (InvokeRequired)
        {
            BeginInvoke(m); // I need to pass txt string in some way here.
        }
        else
        {
            Invoke(m); // I need to pass txt string in some way here.
        }

4 个答案:

答案 0 :(得分:2)

如果这是您的常见情况,我建议您编写一个扩展方法:

public static class ControlExtensions
{
  public static void EnsureInvokeAsync(this Control control, Action action)
  {
     if (control.InvokeRequired) control.BeginInvoke(action);
     else action();
  }
}

class MyControl : UserControl
{
    void M(string s)
    {
       // the lambda will capture the string in a closure
       // the compiler does all the hard work for you
       this.EnsureInvokeAsync(() => _button.Text = s);
    }
}

此外,您应该考虑使用BackgroundWorker或任务进行异步操作。

答案 1 :(得分:1)

MethodInvoker是一个没有任何参数的委托类型。如果我理解正确,你可以这样做:

string txt = "some text";
MethodInvoker m = () => { login_submit.Text = txt; };

答案 2 :(得分:1)

如果InvokeRequired为false,那么你根本不必担心调用任何东西 - 你已经在正确的线程上了。

更好的解决方案可能是这样的:

public delegate void InvokerDelegate(string data);
public void DoStuff(string data){
  login_submit.Text = data;
}

然后在调用它时:

if (InvokeRequired){
  Invoke(InvokerDelegate(DoStuff), "something");
}
else{
  DoStuff("Something");
}

您将看到的一个相当常见的模式是对在多线程环境中操作GUI的函数执行类似的操作

public delegate void InvokerDelegate();
public void DoGuiStuff(){
  if (login_submit.InvokeRequired){
    login_submit.Invoke(InvokerDelegate(DoGuiStuff));
    return;  
  }

  login_submit.Text = "Some value";
}

如果使用上述模式,函数将检查是否需要调用,如果是,则在右侧线程上调用自身。然后它返回。当它调用自己时,检查是否需要调用返回false,因此它不会再次调用它自己 - 它只是运行代码。

编辑:我刚回到winforms并尝试使用该模式只花了几个令人沮丧的时间试图弄清楚为什么我不能调用lambda。我想我最好回来并更新这个答案,以便在其他人试图使用它时添加所需的演员。

答案 3 :(得分:0)

您可以使用闭包将值传递给lambda的主体。

string value = "Login";
MethodInvoker m = () => { login_submit.Text = value; };
if (InvokeRequired)
{
    BeginInvoke(m); // I need to pass txt string in some way here.
}
else
{
    Invoke(m); // I need to pass txt string in some way here.
}

或者您可以使用班级成员的数据

相关问题