C# 带输入参数的 Control.Invoke

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/783925/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 01:00:24  来源:igfitidea点击:

Control.Invoke with input Parameters

c#winformsmultithreading

提问by Adam Haile

From what I've found in C#, the Control.Invoke method requires that you use a delegate with no input parameters. Is there any way around this? I would like to invoke a method to update the UI from another thread and pass to string parameters to it.

根据我在 C# 中的发现,Control.Invoke 方要求您使用没有输入参数的委托。有没有办解决?我想调用一个方来从另一个线程更新 UI 并将字符串参数传递给它。

采纳答案by Samuel

Which version of C# are you using? If you are using C#3.5 you can use closures to avoid passing in parameters.

您使用的是哪个版本的 C#?如果您使用的是 C#3.5,您可以使用闭包来避免传入参数。

使用 C#3.5
public static class ControlExtensions
{
  public static TResult InvokeEx<TControl, TResult>(this TControl control,
                                             Func<TControl, TResult> func)
    where TControl : Control
  {
    return control.InvokeRequired
            ? (TResult)control.Invoke(func, control)
            : func(control);
  }

  public static void InvokeEx<TControl>(this TControl control,
                                        Action<TControl> func)
    where TControl : Control
  {
    control.InvokeEx(c => { func(c); return c; });
  }

  public static void InvokeEx<TControl>(this TControl control, Action action)
    where TControl : Control
  {
    control.InvokeEx(c => action());
  }
}

Safely invoking code now becomes trivial.

安全调用代码现在变得微不足道。

this.InvokeEx(f => f.label1.Text = "Hello World");
this.InvokeEx(f => this.label1.Text = GetLabelText("HELLO_WORLD", var1));
this.InvokeEx(() => this.label1.Text = DateTime.Now.ToString());


使用 C#2.0,它变得不那么琐碎
public class MyForm : Form
{
  private delegate void UpdateControlTextCallback(Control control, string text);
  public void UpdateControlText(Control control, string text)
  {
    if (control.InvokeRequired)
    {
      control.Invoke(new UpdateControlTextCallback(UpdateControlText), control, text);
    }
    else
    {
      control.Text = text;
    }
  }
}

Using it simple, but you have to define more callbacks for more parameters.

使用起来很简单,但是你必须为更多的参数定义更多的回调。

this.UpdateControlText(label1, "Hello world");

回答by Sorin Comanescu

I think Samuel's (excellent) approach can be pushed even more:

我认为塞缪尔 (Samuel) 的(优秀)方可以进一步推广:

Extension Method:

扩展方:

public static void ExecuteAsync<TControl>(this TControl control, Action action)
where TControl : Control
{
  new Thread(() =>
  {
    control.Invoke(action);
  })
  .Start();
}

Form code:

表格代码:

private void doStuff()
{
  this.ExecuteAsync(() =>
  {
    // Do your stuff in a separate thread
    // but having full access to local or instance variables.

    // No (visible) threading code needs to be used here.
  });
}

回答by Tim

As Luke says, use Control.Invoke like this...

正如卢克所说,像这样使用 Control.Invoke ......

For example in a form:

例如在一个表格中:

public delegate void DelegatePassMessages(string name, int value);

public DelegatePassMessages passMessage;

In the contructor:

在构造函数中:

passMessage = new DelegatePassMessages (this.MessagesIn);

Then the MessagesIn function to receive data:

然后是 MessagesIn 函数来接收数据:

public void MessagesIn(string name, int value)
{

}

Then to pass data to your form:

然后将数据传递给您的表单:

formName.Invoke(formName.passMessage, new Object[] { param1, param2});

回答by gsharp

Found an elegant method for .net 2.0 with anonymous methods wrapped in a MethodInvoker Delegate. That way is no need to define own delegates all the time. Example:

找到了一种适用于 .net 2.0 的优雅方,其中匿名方包含在 MethodInvoker Delegate 中。这样就不需要一直定义自己的委托了。例子:

    private void InitUI(Guid id, string typename)
    {
        MethodInvoker inv = delegate{tvMatrix.Nodes[0].Nodes.Add(id.ToString(), typename);};
        tvMatrix.Invoke(inv);
    }

回答by Makah

Why not

为什么不

tvMatrix.Invoke((MethodInvoker) (() => {
    tvMatrix.Nodes[0].Nodes.Add(id.ToString(), typename);
}));

回答by Denis T

Some more possibilities:

还有一些可能性:

this.Invoke(new MethodInvoker(() => this.DoSomething(param1, param2)));

or

或者

this.Invoke(new Action(() => this.DoSomething(param1, param2)));

or even

甚至

this.Invoke(new Func<YourType>(() => this.DoSomething(param1, param2)));

where the first option is the best one, because MethodInvoker is concepted for that purposes and has a better performance.

其中第一个选项是最好的,因为 MethodInvoker 是为此目的而设计的,并且具有更好的性能。

回答by Latency

Here ya go using lambda expressions with the Invoke() extension + an input parameter.

在这里,您可以使用带有 Invoke() 扩展 + 输入参数的 lambda 表达式。

Using: action(STARS db)

使用:动作(STARS db)

_ccb.GetImagerFRU_PartNbr().Invoke(new Action<STARS>(dbase => _ccb.GetImagerFRU_PartNbr().Text = dbase.PartNumber(serial) ?? String.Empty), db);

回答by focus jung

    private void ppTrace(string tv)
    {
        if (_Txb1.InvokeRequired)
        {
            _Txb1.Invoke((Action<string>)ppTrace, tv);
        }
        else
        {
            _Txb1.AppendText(tv + Environment.NewLine);
        }
    }