Reputation: 1747
Could someone please help me with the following problem:
There are two classes MainForm and LWriter. Below is a method from the LWriter that in addition to writing to a file sends some updates to a RichTextBox control (through mainForm.UpdateLog(text)). Everything works fine, however, this WriteOutput method also does some extensive processing that during the calculation freezes the form.
I think the WriteOutput should be encapsulated in a separate thread. Could someone please help me out explaining how to place WriteOutput (LWriter class) in a thread that will then call mainForm.UpdateLog() from the mainFrom in a safe manner?
I am new to threads, thus help would be much appreciated.
public void WriteOutput(string output, Links[] links)
{
try {
using (StreamWriter sw = new StreamWriter(output)) {
for (int x= 1; x<links.Length;x++) {
...
sw.WriteLine( ... );
sw.Flush();
}
mainForm.UpdateLog(<text>);
}
} catch(Exception e) { ... }
}
Upvotes: 4
Views: 10547
Reputation: 891
As suggested by Sonu, delegate
can be used for Thread safe calls, and you can use Linq to shorten the code:
this.BeginInvoke( (Action) delegate ()
{
//code to update UI
});
See this link for more information.
Upvotes: 3
Reputation: 2161
delegate
can be used for Thread safe calls
Check this http://msdn.microsoft.com/en-us/library/ms171728.aspx
// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void SetTextCallback(string text);
// This method demonstrates a pattern for making thread-safe
// calls on a Windows Forms control.
//
// If the calling thread is different from the thread that
// created the TextBox control, this method creates a
// SetTextCallback and calls itself asynchronously using the
// Invoke method.
//
// If the calling thread is the same as the thread that created
// the TextBox control, the Text property is set directly.
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
Upvotes: 3
Reputation: 51329
Interactions with UI controls must be done on the UI thread. You can build the string on a background thread, but you should use Control.Invoke or Control.BeginInvoke to marshal to the UI thread before interacting with it.
Lots of examples of this on the net and stack overflow.
Upvotes: 0
Reputation: 62439
Typically you should run this kind of time-consuming operations in a BackgroundWorker
. Define a work method:
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// execute your WriteOutput method
}
and set is as the DoWork
event handler:
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync(); // start the worker
To safely update the UI from a different thread use the Control.BeginInvoke
method:
mainForm.BeginInvoke(
() => { mainForm.UpdateLog(<text>); });
Upvotes: 7