WPF: How to handle errors with a BackgroundWorker - wpf

I am a bit of a newbie when it comes to windows client programming. I have a background worker that has a DoWork event and a RunCompleted event wired up. If an exception gets thrown in DoWork, I want to make changes to my UI, however, I cant because it is in a different thread. I can communicate the error to RunCompleted, but that doesn't help me either.

call Dispatcher.BeginInvoke. Basically, you want code like this:
void UpdateState(WhatEverType someObject)
{
if (! Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>UpdateState(someObject));
}
else
{
//make the UI changes here.
}
}

Related

Freeze WPF UI - multi-threading in view model class

Hi I use WPF with Caliburn Micro and in view model class I need test connection to SQL database.
Here is method which I use for testing connection.
public bool CheckSqlServer(string sqlHost, int sqlPort)
{
try
{
IPHostEntry ipHost = Dns.Resolve(sqlHost);
IPAddress ipAddr = ipHost.AddressList[0];
var tcpCli = new TcpClient();
tcpCli.Connect(ipAddr, sqlPort);
tcpCli.Close();
return true;
}
catch
{
return false;
}
}
And I call this method in another thread
//IP is worng
if (Task<bool>.Factory.StartNew(()=>CheckSqlServer("10.10.10.20",1521)).Result)
{
Insert();
}
Problem is that UI of WPF still freeze I dont know why because I call this method in new thread not in UI thread.
In your if you call Result straight away. That makes the calling thread wait on the task in a blocking way.
You should work e.g. with ContinueWith on the Task. That will be called once the execution of the first task finished. Careful with SynchronizationContext, though!
Also, you shouldn't call TaskFactory etc. in another thread. The whole point of Task is to abstract parallelism away from using the 'low-level' threads.
Try to set the proxy to null, so that the default auto-discovery will be disabled.
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.proxy.aspx

Calling thread cannot access object because different thread owns it

I thought I knew what causes this exception until I wrote this:
var menu = ViewConfigHelper.CreateObjectFromResource<Menu>(config, baseURI);
if (!menu.Dispatcher.CheckAccess())
{
throw new ArgumentException("Somethign wrong");
}
if (!LayoutRoot.Dispatcher.CheckAccess())
{
throw new ArgumentException("SOmethign wrong");
}
// exception throw here
LayoutRoot.Children.Insert(0, menu);
First line creates a Menu control from an embedded XAML file. Both CheckAccess calls return true. However, when last line is executed, an exception is thrown with the message "Caling thread cannot access object because differrent thread owns it." The code above is being executed within a method called immediately after InitializeComponent() that created LayoutRoot, on the same thread, I believe.
Someone please enlighten me. I am trying to create a multiple UI thread WPF app.
You are using CheckAccess() in reverse. You want to lose the ! signs before each check. See the example bit of code on the CheckAccess() MSDN page.
In the Winforms world you'd do a InvokeRequired() which is now the same thing as a !CheckAccess(). In your case because both values are returning true, and you are inverting them, neither if block is hit.
To expand a bit... in the Winforms world, the normal patter was:
if(InvokeRequired)
{
Invoke(...);
}
else
{
//do work
}
(or sometimes a return after invoke, if it was invoking the same method).
In WPF, CheckAccess() is similar to, but not identical to InvokeRequired... there for a pattern more along the lines of:
if (someUiControl.Dispatcher.CheckAccess())
{
//Doing an update from this thread is safe, so we can do so here.
}
else
{
// This thread does not have access to the UI thread.
// Call the update thread via a Dispatcher.BeginInvoke() call.
}
The key difference between is that InvokeRequired() returning true meant it was UNSAFE to do the update in the current thread... while a true from CheckAccess() means it is SAFE.

Confused by the behavior of Dispatcher.BeginInvoke()

Could someone shed some light on an issue I'm having?
I'm working on a wpf project. The scenario is as below:
I need to pop up a window(model window) on main UI thread and then close it. These works are started from another UI thread (to deter user from clicking on the main UI window.) then I close this window. The main code are displayed below. And it works.
As far as I know the close method would not get excuted before ShowDialog() returns (at least this is the case on UI thread, I mean code without dispatcher), does anyone have experience with multithread?
Window window;
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
//create a window and let user work from this thread
//code is omitted.
//create another window on main UI thread
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
//do some work here
Thread.Sleep(1000);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
//Thread.Sleep(1000);
window.Close();
}));
});
thread.Start();
}
Thank you for your time!
So if I understand your question correctly, you're saying that this code works exactly the way you want, but you're just trying to understand how (and why) it works?
Here's how it works. First, your thread runs this code:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window = new Window();
window.ShowDialog();
}));
That queues your action on the main (UI) thread's dispatcher queue, and then returns immediately: your worker thread continues running.
When the Application first started up (typically via the compiler-generated code that initializes your App.xaml object, though you can also do it explicitly by calling Application.Run), it started its message loop, which goes something like this (pseudocode, very very simplified):
public class Application {
public void Run() {
while (!Exited && action = Dispatcher.DequeueAction())
action();
}
}
So at some point shortly after you queue the action, the UI thread will get around to pulling your action off the queue and running it, at which point your action creates a window and shows it modally.
The modal window now starts its own message loop, which goes something like this (again, very simplified):
public class Window {
public bool? ShowDialog() {
DisableOtherWindowsAndShow();
while (!IsClosed && action = Dispatcher.DequeueAction())
action();
EnableOtherWindowsAndHide();
return DialogResult;
}
}
Later, your worker thread runs this code:
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
window.Close();
}));
Again, your action is queued to the UI thread's dispatcher queue, and then the BeginInvoke call returns immediately and your worker thread continues running.
So sooner or later, the UI thread's message loop will get around to dequeuing and executing your action, which tells the window to close. This has essentially the same effect as the user clicking the title bar's "X" button, which of course is perfectly OK to do even when you're inside a modal dialog. This causes ShowDialog's message loop to terminate (because the window is now closed), at which point the dialog is hidden and the other windows are re-enabled, ShowDialog returns, your original (ShowDialog) action is complete and so returns, and control falls back to the original message loop in Application.Run.
Note that there's one dispatcher queue per thread, not one per message loop. So your "close" action goes into the same queue that your "show dialog" action did. It's a different piece of code doing the message-loop polling now (the one inside ShowDialog instead of the one inside Application.Run), but the basics of the loop are the same.
BeginInvoke is a non-blocking method; it adds the action to the dispatcher queue, and doesn't wait for its completion. You should use Invoke instead, which calls the method synchronously on the dispatcher thread.

Calling a webservice synchronously from a Silverlight 3 application?

I am trying to reuse some .NET code that performs some calls to a data-access-layer type service. I have managed to package up both the input to the method and the output from the method, but unfortunately the service is called from inside code that I really don't want to rewrite in order to be asynchronous.
Unfortunately, the webservice code generated in Silverlight only produces asynchronous methods, so I was wondering if anyone had working code that managed to work around this?
Note: I don't need to execute the main code path here on the UI thread, but the code in question will expect that calls it makes to the data access layers are synchronous in nature, but the entire job can be mainly executing on a background thread.
I tried the recipe found here: The Easy Way To Synchronously Call WCF Services In Silverlight, but unfortunately it times out and never completes the call.
Or rather, what seems to happen is that the completed event handler is called, but only after the method returns. I am suspecting that the event handler is called from a dispatcher or similar, and since I'm blocking the main thread here, it never completes until the code is actually back into the GUI loop.
Or something like that.
Here's my own version that I wrote before I found the above recipe, but it suffers from the same problem:
public static object ExecuteRequestOnServer(Type dalInterfaceType, string methodName, object[] arguments)
{
string securityToken = "DUMMYTOKEN";
string input = "DUMMYINPUT";
object result = null;
Exception resultException = null;
object evtLock = new object();
var evt = new System.Threading.ManualResetEvent(false);
try
{
var client = new MinGatServices.DataAccessLayerServiceSoapClient();
client.ExecuteRequestCompleted += (s, e) =>
{
resultException = e.Error;
result = e.Result;
lock (evtLock)
{
if (evt != null)
evt.Set();
}
};
client.ExecuteRequestAsync(securityToken, input);
try
{
var didComplete = evt.WaitOne(10000);
if (!didComplete)
throw new TimeoutException("A data access layer web service request timed out (" + dalInterfaceType.Name + "." + methodName + ")");
}
finally
{
client.CloseAsync();
}
}
finally
{
lock (evtLock)
{
evt.Close();
evt = null;
}
}
if (resultException != null)
throw resultException;
else
return result;
}
Basically, both recipes does this:
Set up a ManualResetEvent
Hook into the Completed event
The event handler grabs the result from the service call, and signals the event
The main thread now starts the web service call asynchronously
It then waits for the event to become signalled
However, the event handler is not called until the method above has returned, hence my code that checks for evt != null and such, to avoid TargetInvocationException from killing my program after the method has timed out.
Does anyone know:
... if it is possible at all in Silverlight 3
... what I have done wrong above?
I suspect that the MinGatServices thingy is trying to be helpful by ensuring the ExecuteRequestCompleted is dispatched on the main UI thread.
I also suspect that your code is already executing on the main UI thread which you have blocked. Never block the UI thread in Silverlight, if you need to block the UI use something like the BusyIndicator control.
The knee-jerk answer is "code asynchronously" but that doesn't satisfy your question's requirement.
One possible solution that may be less troublesome is to start the whole chunk of code from whatever user action invokes it on a different thread, using say the BackgroundWorker.
Of course the MinGatServices might be ensuring the callback occurs on the same thread that executed ExecuteRequestAsync in which case you'll need to get that to run on a different thread (jumping back to the UI thread would be acceptable):-
Deployment.Current.Dispatcher.BeginInvoke(() => client.ExecuteRequestAsync(securityToken, input));

Control.IsAccessible

I need to check if a c# WinForm Window (FORM Class) has been initialized and waiting for user events. But I could not find out how to manage that.
Therefore I had the idea to set the Control.IsAccessible Flag of the Form to true, within the OnLoad Event of the Windows Form.
My question is now, what is the Control.IsAccessible Flag origin intended for? Or is there an other solution to check if the Winform is initialized.
Thanks for your help
I do not know what IsAccessible is intended for but for the check you are doing you want Created
if(myForm.Created)
{
//Do stuff
}
I had a whole bunch of problems with it, here is one of my old question on SO that helped me out a lot with it.
Control.IsAccessible just means the control is visible to accessibility applications.
You can check myForm.Created to see if the window exists.
You can also register an event handler for the Application.Idle event, which occurs when the application has finished initializing and is ready to begin processing windows messages.
Here is a common usage:
public int Main(string[] args)
{
Application.Idle += WaitUntilInitialized;
}
private void WaitUntilInitialized(object source, EventArgs e)
{
// Avoid processing this method twice
Application.Idle -= WaitUntilInitialized;
// At this point, the UI is visible and waiting for user input.
// Begin work here.
}

Resources