从多线程类到Windows ActiveForm的事件文本回发

时间:2011-10-21 18:26:05

标签: c# .net winforms multithreading events

所以我有一个有趣的问题(无论如何)。我正在编写一个运行扫描的应用程序,并将类中的信息发布回Windows窗体。现在我正在创建一个表单实例,访问ActiveForm,然后将一些文本发布到该表单中的公共函数。

Scan.cs

// Sets the text of scan history in the ui
private void SetScanHistory(string text)
{
    MyWinForm1 form = (MyWinForm1)MyWinForm1.ActiveForm;

    if (form != null)
    {
        form.SetText(text);
    }
}

MyWinForm1.cs

// Sets the text of txtScanHistory to the text 
public void SetText(string text)
{
    this.Invoke((MethodInvoker)delegate
    {
        // txtScanHistory is a TextBox
        txtScanHistory.Text += text + Environment.NewLine;
    });
}

所以现在这个效果非常好。问题是当用户将焦点从Windows窗体更改为文本停止更新时,这就是为什么我有“if(form!= null)”。我知道这不是我想要做的事情的理想方式,所以我的问题是如何将此代码更改为“MyWinForm1”中的自定义事件?或者,如果还有其他方法可以做到这一点,我很乐意看到一些替代方案。

2 个答案:

答案 0 :(得分:1)

有几种方法可以达到你想要的效果。

1)您可以添加对目标表单的引用作为Scan.cs类的属性

    public MyWinForm1 WinFormReference { get; set; }

    // Sets the text of scan history in the ui
    private void SetScanHistory(string text)
    {
        if (this.WinFormReference != null)
        {
            this.WinFormReference.SetText(text);
        }
    }

然后你可以将你的扫描类的引用传递给WinForm1实例并设置相应的属性[在这种情况下我使用WinForm构造函数传递扫描器类]:

  public void WinForm1(Scan scanner)
  {
      if (scanner != null) scanner.WinFormReference = this;
  }

2)您可以将自定义事件添加到扫描类,然后将代理挂钩到WinForm中的回调[再次,您的WinForm将需要引用您的扫描类]:

public class SetScanHistoryEvents: EventArgs
{
    public SetScanHistoryEvents(string text)
    {
        this.Text = text;
    }

    public string Text { get; set; }
}

public class Scan
{
    public event EventHandler<SetScanHistoryEvents> ScanHistoryEvent;

    // Sets the text of scan history in the ui
    private void SetScanHistory(string text)
    {
        if (this.ScanHistoryEvent != null)
        {
            this.ScanHistoryEvent(this, new SetScanHistoryEvents(text));
        }
    }
}

然后你在表单的构造函数(或其他地方)中挂钩回调:

    public MyWinForm1(Scan scanner)
    {
        if (scanner != null)
            scanner.ScanHistoryEvent += new EventHandler<SetScanHistoryEvents>(scanner_ScanHistoryEvent);
    }

    private void scanner_ScanHistoryEvent(object sender, SetScanHistoryEvents e)
    {
        this.Invoke((MethodInvoker)delegate
        {
            // txtScanHistory is a TextBox
            txtScanHistory.Text += text + Environment.NewLine;
        });
    }

答案 1 :(得分:0)

您可以使用SynchronizationContext

之类的内容
public partial class Form1 : Form
    {
        SynchronizationContext context;
        public Form1()
        {
            InitializeComponent();
            context = SynchronizationContext.Current;
        }
        // Sets the text of scan history in the ui
        private void SetScanHistory(string text)
        {
            CallFunc(text);
        }
        private void CallFunc(string TextValue)
        {            
            context.Post(new SendOrPostCallback(
            delegate
            {
                textBox1.Text += TextValue + Environment.NewLine;
            }), TextValue);
        }
    }