使用来自C#中不同线程的Invoke访问类成员

时间:2009-04-04 17:28:42

标签: c# winforms multithreading invoke

注意:系列文章的一部分:C#: Accessing form members from another classHow to access form objects from another cs file in C#


您好,

想法是在TCP客户端接收/发送数据包时使用备忘录通知用户。

经过几次修复,最合适的解决方案似乎就是这个

    public string TextValue
    {
        set
        {
            this.Memo.Text += value + "\n";
        }
    }

这就是它被称为

的方式
    var form = Form.ActiveForm as Form1;
    if(form != null)
        form.TextValue = "Test asdasd";

然而,由于不安全的线程调用,调用代码会引发异常。我在msdn找到了一个解决方案,但我似乎无法获得他们在那里使用的方法。

这是我的翻拍,但不起作用。

    private void SetTextMemo(string txt)
    {
        if(this.Memo.InvokeRequired)
        {
            this.Invoke(SetTextMemo,txt); //error here
        }
        else
        {
            this.Memo.Text += txt + "\n";
        }
    }

错误:

参数'1':无法从'方法组'转换为'System.Delegate'

参数'2':无法从'string'转换为'object []'

基本上,我正在尝试使用Invoke从另一个线程访问备忘录(或者更可能是说,在备忘录中添加文本)。我以前从未使用它,也许这就是我误解了我的错误的原因。

4 个答案:

答案 0 :(得分:11)

简单的方法是:

this.Invoke((MethodInvoker)delegate {
    this.Memo.Text += txt + "\n";
});

使用匿名方法进行内联工作。由于你期望在另一个线程上,你也可以只调用Invoke - 它甚至可以从UI线程安全。

答案 1 :(得分:1)

如果您正在使用C#3.0和3.5框架,请尝试以下

if ( this.Memo.InvokeRequired ) {
  this.Invoke((Action)(() => SetTextMemo(txt)));
} 

答案 2 :(得分:1)

您的实现假定该方法不会无限递归,因为InvokeRequired属性的行为将阻止它。这种假设可能是正确的,但编码函数以完全避免这种可能性是没有问题的。这是我的建议:

    private void SetMemo(string txt)
    {
        Memo.Text = txt;
    }

    private delegate void MemoSetter(string txt);

    public void ThreadSafeSet(string txt)
    {
        Invoke(new MemoSetter(SetMemo), txt);
    }

答案 3 :(得分:0)

我曾经处理过所有这些跨线程的业务,但最近我选择了AOP,在那里你只需装饰一个在UI线程上执行的方法。这是一个例子(来自PostSharp):

public class FormsThreadAttribute : OnMethodInvocationAspect
{
  public override void OnInvocation(MethodInvocationEventArgs eventArgs)
  {
    Form f = (Form)eventArgs.Delegate.Target;
    if (f.InvokeRequired)
      f.Invoke(eventArgs.Delegate, eventArgs.GetArgumentArray());
    else
      eventArgs.Proceed();
  }
}