Reputation: 3213
This is probably a silly question, but I could not find an answer on stackoverflow.
I have a button click event in a Winform app that runs a thread to caclulate a result to display in a form.
How do I update the Forms UI when the thread has calculated the result?
private void btnRequestR2Approval_Click(object sender, EventArgs e)
{
if (User.IsLogged)
{
ValidationResults results = new ValidationResults();
results.Show();
Logger log = Logger.Instance();
Logger.NewLogAddedHandler messageDelegate = new Logger.NewLogAddedHandler(results.NewLogMessage);
if (!log.IsEventHandlerRegistered())
{
log.NewLogAdded += messageDelegate;
}
ThreadStart operation = new ThreadStart(ValidateAndSubmit);
Thread theThread = new Thread(operation);
theThread.Start();
}
else
{
MessageBox.Show("Please login");
}
}
Thank you
Upvotes: 5
Views: 12704
Reputation: 56230
The simplest technique for executing a background task in WinForms is to use a BackgroundWorker.
DoWork
. You'll probably also want RunWorkerCompleted
.DoWork
event. RunWorkerCompleted
event.backgroundWorker1.RunWorkerAsync();
to kick off the process, probably from some button handler.Using a BackgroundWorker avoids all the annoying thread handling and IsInvokeRequired stuff.
Here's a more detailed how-to article.
Upvotes: 16
Reputation: 21722
Very unclear question, I will assume:
If that is true, you should be using an asynchronous delegate, not a thread. For example:
string SleepAndReturnParam(string param1)
{
System.Threading.Thread.Sleep(10000);
return param1;
}
// Declare a delegate matching our async method.
public delegate string DelegateWithParamReturningString(string param1);
private void button1_Click(object sender, EventArgs e)
{
var myDelegate = new DelegateWithParamReturningString(SleepAndReturnParam);
// Run delegate in thread pool.
myDelegate.BeginInvoke("param1",
OnCallBack, // Completion callback
this); // value to pass to callback as AsyncState
}
private void OnCallBack(IAsyncResult ar)
{
// first cast IAsyncResult to an AsyncResult object
var result = ar as System.Runtime.Remoting.Messaging.AsyncResult;
// grab the delegate
var myDelegate = result.AsyncDelegate as DelegateWithParamReturningString;
// Exit delegate and retrieve return value.
string returnValue = myDelegate.EndInvoke(ar);
// Declare an anonymous method to avoid having to define
// a method just to update a field.
MethodInvoker formFieldUpdater = delegate
{
formTextField.Text = returnValue;
};
// Winforms controls must be modified on the thread
// they were created in.
if (formTextField.InvokeRequired)
Invoke(formFieldUpdater);
else
formFieldUpdater();
}
Upvotes: 2
Reputation: 9861
Try using a BeginInvoke with a callback operation... this will push your call to another thread, and call a method of your choosing when the thread completes:
private void btnRequestR2Approval_Click(object sender, EventArgs e)
{
if (User.IsLogged)
{
ValidationResults results = new ValidationResults();
results.Show();
Logger log = Logger.Instance();
Logger.NewLogAddedHandler messageDelegate = new Logger.NewLogAddedHandler(results.NewLogMessage);
if (!log.IsEventHandlerRegistered())
{
log.NewLogAdded += messageDelegate;
}
ThreadStart operation = new ThreadStart(ValidateAndSubmit);
operation.BeginInvoke(MyCallBack, this);
}
else
{
MessageBox.Show("Please login");
}
}
private static void MyCallBack(IAsyncResult ar) {
((MyForm)ar.AsyncState).Refresh();
}
Upvotes: 2
Reputation: 3340
You can either
1. do a theThread.Join()
which would block the calling thread.
2. Pass the first thread through to the second so it can make a call back into the main thread, which would need to do an Invoke()
so it can redraw the form.
I'm curious though. Are you using Asp.Net (WebForms) or WinForms? If you are trying to do this on the web then you will need a completly different approach.
Upvotes: 0