开发者

MethodInvoker + lambda + arguments + CrossThread Operation

开发者 https://www.devze.com 2023-02-28 22:17 出处:网络
I\'m using this to change something on other thread: MethodInvoker m = () => { login_submit.Text = \"Login\"; };

I'm using this to change something on other thread:

        MethodInvoker m = () => { login_submit.Text = "Login"; };
        if (InvokeRequired)
        {
            Begi开发者_如何学GonInvoke(m);
        }
        else
        {
            Invoke(m);
        }

this is working fine.

How can I pass argumets to that lamba expression?

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.


If InvokeRequired is false then you don't need to worry about invoking anything at all - you're already on the right thread.

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

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.

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. I thought I'd better come back and update this answer to add the required casting in case anyone else tried to use it.


MethodInvoker is a delegate type that doesn't have any parameters. If I understand you correctly, you can do it like this:

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


You can use closures to pass the value into the lambda's body.

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

0

精彩评论

暂无评论...
验证码 换一张
取 消