2

注意:系列的一部分:C#:从另一个类访问表单成员以及如何在 C# 中从另一个 cs 文件访问表单对象


你好,

这个想法是在 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 从另一个线程访问备忘录(或者更有可能是在备忘录中添加文本)。我以前从未使用过它,也许这就是我误解我的错误的原因。

4

4 回答 4

11

简单的方法是:

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

它使用匿名方法在线完成工作。由于您希望在另一个线程上,您不妨只调用 Invoke - 即使从 UI 线程也是安全的。

于 2009-04-04T17:30:43.553 回答
1

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

if ( this.Memo.InvokeRequired ) {
  this.Invoke((Action)(() => SetTextMemo(txt)));
} 
于 2009-04-04T17:32:10.927 回答
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);
    }
于 2009-04-04T17:41:50.873 回答
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();
  }
}
于 2009-04-04T17:32:57.477 回答