方法调用者 +拉姆达 +论据 +跨线程操作

发布于 2024-11-03 09:11:53 字数 642 浏览 2 评论 0原文

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

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

这工作正常。

我怎样才能将参数传递给那个巴巴表达式?

我想做那样的事情:

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

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?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

余厌 2024-11-10 09:11:53

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

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 或任务进行异步操作。

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.

如果没有你 2024-11-10 09:11:53

如果 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。我想我最好回来更新这个答案以添加所需的转换,以防其他人尝试使用它。

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.

欢烬 2024-11-10 09:11:53

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

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

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; };
话少心凉 2024-11-10 09:11:53

您可以使用闭包将值传递到 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.
}

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文