问题
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