简体   繁体   English

MethodInvoker + lambda +参数+ CrossThread操作

[英]MethodInvoker + lambda + arguments + CrossThread Operation

I'm using this to change something on other thread: 我正在使用它来更改其他线程上的某些内容:

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

this is working fine. 这很好。

How can I pass argumets to that lamba expression? 如何将argumets传递给该lamba表达式?

I want to do sth like that: 我想做这样的事情:

        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.
        }

If this is a common scenario for you, I suggest writing an extension method: 如果这是您的常见情况,我建议编写一个扩展方法:

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);
    }
}

Also, you should look into using BackgroundWorker or tasks for async operations. 另外,您应该研究使用BackgroundWorker或任务进行异步操作。

MethodInvoker is a delegate type that doesn't have any parameters. MethodInvoker是没有任何参数的委托类型。 If I understand you correctly, you can do it like this: 如果我对您的理解正确,则可以这样进行:

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

If InvokeRequired is false then you don't need to worry about invoking anything at all - you're already on the right thread. 如果InvokeRequired为false,那么您根本不必担心调用任何东西-您已经在正确的线程上。

A better solution might be something like this: 更好的解决方案可能是这样的:

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

and then when calling it do: 然后在调用它时执行:

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

A fairly common pattern you will see is to do something like this for functions that manipulate the GUI in a multithreaded environment 您将看到的一种相当常见的模式是对在多线程环境中操纵GUI的函数执行类似的操作

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

  login_submit.Text = "Some value";
}

If you use the above pattern the function checks to see if an invoke is required and if so Invokes itself on the right thread. 如果使用上述模式,该函数将检查是否需要调用,如果需要,则在正确的线程上调用自身。 It then returns. 然后返回。 When it invokes itself the check to see if an invoke is required returns false so it doesn't bother invoking itself again - it just runs the code. 当它调用自身时,检查是否需要调用将返回false,因此它不会再次调用自身-它仅运行代码。

Edit: I just went back to winforms and tried to use that pattern only to spend a couple of frustrating minutes trying to work out why I couldn't invoke a lambda. 编辑:我只是回到了winforms,试图使用该模式只是花了一些令人沮丧的时间,试图弄清楚为什么我不能调用lambda。 I thought I'd better come back and update this answer to add the required casting in case anyone else tried to use it. 我以为最好再返回并更新此答案以添加所需的转换,以防其他人尝试使用它。

You can use closures to pass the value into the lambda's body. 您可以使用闭包将值传递给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.
}

or you can use class member's data 或者您可以使用班级成员的数据

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM