Event Text Postback from Multithreaded Class to Windows ActiveForm

半腔热情 提交于 2020-01-16 13:47:21

问题


So I have an interesting problem (to me anyway). I am writting an application that runs a scan and posts information from a class back to a Windows Form. Right now I am creating an instance of a form, accessing the ActiveForm, then posting some text to a public function in that form.

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;
    });
}

So right now this works pretty well. The problem is when the user changes focus away from the Windows Form the text stops updating, which is why I have "if (form != null)". I know this is not an ideal way to do what I am trying to do, so my question is how can I change this code to be something like a custom event in "MyWinForm1"? Or, if there is any other way to do this I would love to see some alternatives.


回答1:


There are a couple ways of achieving what you want.

1) You can add a reference to the target form as a property of Scan.cs class

    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);
        }
    }

then you can pass the reference to your scan class into the WinForm1 instance and set the appropriate property [in this case I'm passing the scanner class using the WinForm constructor]:

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

2) You can add a custom event to the scan class and then hook the delegate to a callback in your WinForm [again, your WinForm will need to have a reference to your scan class]:

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));
        }
    }
}

Then you hook up the callback in your form's constructor (or elsewhere):

    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;
        });
    }



回答2:


You can have something like following which use 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);
        }
    }


来源:https://stackoverflow.com/questions/7853669/event-text-postback-from-multithreaded-class-to-windows-activeform

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!