Reputation: 13
I'm trying to animate a loading screen while thread is working in background, but it won't work.
I realized that it has something to do with the backgroundworker calling Button.Dispatcher, however I can't remove it, because it would cause threading error. What should I do to fix this?
below is my code:
private void btnLogin_Click(object sender, RoutedEventArgs e)
{
Storyboard sb = (Storyboard)FindResource("Loading");
sb.Dispatcher.BeginInvoke(new Action(() => sb.Begin()), DispatcherPriority.Normal, null);
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerAsync();
}
private void bg_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(RunThread));
thread.Start();
}
private void RunThread()
{
btnLogin.Dispatcher.BeginInvoke(new Action(() => TheBackgroundWork()), DispatcherPriority.Normal, null);
}
Update:
I remove UI calls from Do_Worker as suggested by Jay. Unfortunately I'm still getting an error:
The calling thread cannot access this object because a different thread owns it.
It was thrown by my webservice client
below is the updated code:
private WebServiceClient proxy = new WebServiceClient();
private void btnLogin_Click(object sender, RoutedEventArgs e)
{
sb = (Storyboard)FindResource("sbLoading");
sb.Dispatcher.BeginInvoke(new Action(() => sb.Begin()), DispatcherPriority.Normal, null);
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
bg.RunWorkerAsync();
}
private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var u = e.Result;
if (u != null)
//pass the data
}
private void bg_DoWork(object sender, DoWorkEventArgs e)
{
try
{
var u = proxy.ToWebService(x,y); //this guy throws an error
e.Result = u;
}
catch
{
this.Dispatcher.Invoke(new Action(
() => MessageBox.Show("Connection Error", this.Title)),
DispatcherPriority.Normal, null);
}
}
Upvotes: 0
Views: 894
Reputation: 57899
bg_DoWork
method will already be running on a background thread, so no need to create a thread in there.bg_DoWork
should touch UI elements nor anything databound to UI elements. If you have some return data, package it up into an object and stuff it into the DoWorkEventArgs.Result
property.BackgroundWorker.RunWorkerCompleted
event. This method will run back on the UI thread, so you can read your response data from the RunWorkerCompletedEventArgs
(this will be the result object that you assigned in #2) and update the UI as necessary.The beauty of BackgroundWorker
is that it will handle thread creation and marshaling of data back to the UI thread -- no need for any Dispatcher.Invoke
.
In response to your edit, the web service call may be throwing an exception, but the thread exception you get is caused by trying to access this
from a background thread.
Just as you'd have to package your success result in DoWorkEventArgs.Result
, you'd need to package a failure result there too.
The object you pass back can be anything, so you can add things like a bool Success
property, an Exception CaughtException
property, etc.
You'll check these values in your RunWorkerCompleted
handler and that is where you would show your MessageBox
.
Upvotes: 1