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);
}
}
bg_DoWorkmethod will already be running on a background thread, so no need to create a thread in there.bg_DoWorkshould 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 theDoWorkEventArgs.Resultproperty.BackgroundWorker.RunWorkerCompletedevent. This method will run back on the UI thread, so you can read your response data from theRunWorkerCompletedEventArgs(this will be the result object that you assigned in #2) and update the UI as necessary.The beauty of
BackgroundWorkeris that it will handle thread creation and marshaling of data back to the UI thread — no need for anyDispatcher.Invoke.Update
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
thisfrom 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 Successproperty, anException CaughtExceptionproperty, etc.You’ll check these values in your
RunWorkerCompletedhandler and that is where you would show yourMessageBox.