【问题标题】:Accessing Class members with Invoke from a different thread in C#使用 Invoke 从 C# 中的不同线程访问类成员
【发布时间】:2009-04-04 17:28:41
【问题描述】:

注意:系列的一部分: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”:无法从“字符串”转换为“对象[]”

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

【问题讨论】:

    标签: c# winforms multithreading invoke


    【解决方案1】:

    简单的方法是:

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

    它使用匿名方法内联完成工作。由于您期望在另一个线程上,因此您也可以调用 Invoke - 即使从 UI 线程也是安全的。

    【讨论】:

    • 这是 Gravell 第二次(但不是最后一次)救了我的培根。为此,你可以在这个星期六休息。我想我也可以在星期天给你什么。
    【解决方案2】:

    如果您使用的是 C# 3.0 和 3.5 框架,请尝试以下操作

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

    【讨论】:

    • 和 .NET 3.5 用于 Action 委托类型;-p
    • @Marc,我一直忘记那是 3.5 类型。为什么它没有在 2.0 中添加,我无法理解 :)
    【解决方案3】:

    您的实现假定该方法不会无限递归,因为 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);
        }
    

    【讨论】:

      【解决方案4】:

      我曾经处理所有这些跨线程业务,但最近我使用 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();
        }
      }
      

      【讨论】:

      • 这是在任何其他方法恕我直言之前肯定应该使用 AOP 的地方。但是对于那些不熟悉 PostSharp 和 AOP 的人来说,可能很难从你的帖子中理解它是如何工作的,以及它的实际使用简单性是什么。
      • 好吧,我会提供指向 PostSharp 相关教材的链接,但实际上我不允许这样做:(
      猜你喜欢
      • 2016-06-03
      • 2011-04-03
      • 2012-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多