I have a non-ui thread that I need to pump messages on.
The normal way to do this would involve a call Dispatcher.Run() in the thread proc of my thread.
I'd like to modify this to make it more robust with regard to unhandled exceptions.
My first cut is:
for (;;)
{
var frame = new DispatcherFrame();
try
{
Dispatcher.PushFrame(frame);
break;
}
catch (Exception e)
{
frame.Continue = false;
Log("ThreadProc caught exception:\n{0}", e);
}
}
This code works and allows the dispatcher to continue pumping messages after an exception.
Does anyone know of any potential problems with this approach?
I find using a dispatcherframe can give some problems when using it with a ui thread - for example problems with focus - I think your scenario will be fine.
Have you tried catching it with:
Application.DispatcherUnhandledException
or
Dispatcher.UnhandledException
You could also try that and set Handled=true to make it continue.
Related
I Have a WPF Project, When i try to Run This Code On RowLoad Event I got below Error :
private void ParentGridView_OnRowLoaded(object sender, EventArgs e)
{
try
{
if(((RadGridView)sender).Columns != null)
{
MessageBox.Show(((RadGridView)sender).Columns.Count.ToString(CultureInfo.InvariantCulture));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Error : Dispatcher processing has been suspended, but messages are still being processed.
Note That the GridView Control is Telerik RadGridView
This answer describes the same situation as yours. (It references this answer on a different website).
The dispatcher processing is suspended to avoid reentrancy problems when updating the visual tree.
If you really need to display a message box in response to your "Row Loaded" event, you need to defer the call using `Dispatcher.BeginInvoke().
So, replace:
MessageBox.Show(((RadGridView)sender).Columns.Count.ToString(CultureInfo.InvariantCulture));
with:
var msg = ((RadGridView)sender).Columns.Count.ToString(CultureInfo.InvariantCulture);
Dispatcher.BeginInvoke(new Action(() => MessageBox.Show(msg)));
If this code is in a WPF object, then the Dispatcher property is available. Otherwise, you need to get it from somewhere else.
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.
I am porting TCPClient into Silverlight and I see that the BeginConnect can throw a SocketException somehow from the asynchronous process.
In silverlight there is a Completed event for the ConnectAsync function which supplies a SocketError in it's SocketAsyncEventArgs parameter.
I am throwing a new SocketException whenever the socket fails to connect from the method my implementation of TCPClient hooked into the Completed event.
The problem lays here:
try
{
var ar = client.BeginConnect(...);
// Do stuff
client.EndConnect(ar);
}
catch(SocketException e)
{
// Handle exception here
}
The exception won't be catched here due to the fact that it is thrown from an event? Or maybe it's because the event is executed on another thread? I'm not sure. In any case the exception is not caught.
Well, this doesn't answer your question directly, but if no one has a better solution, you can create your own thread and do a Connect instead of a BeginConnect. Then, you should be able to catch the exception.
You should do a lambda to capture the errors as shown here:
http://social.msdn.microsoft.com/Forums/hu-HU/csharpgeneral/thread/0fbe2ebd-a576-4ac5-a1ed-a5d13d0cd9c8
In my application I have a main windows and into it, in a frame I load a page. This page do a long time task when the user press a button. My problem is that when long task is being doing and the user presses the close button of the main window, the application seems to not finish because I am debugging it in VS2008 and I can see the stop button highlighted. If I want to finish I have to press stop button, the application doesn't stop the debugging automatically on application exit. I thought .NET stops automatically backgroundworkers on application exits but I am not sure after seeing this behaviour. I have tried to force and cancel background worker in unloaded event page with something like this:
private void Page_Unloaded(object sender, RoutedEventArgs e)
{
// Is the Background Worker do some work?
if (My_BgWorker != null && My_BgWorker.IsBusy)
{
//If it supports cancellation, Cancel It
if (My_BgWorker.WorkerSupportsCancellation)
{
// Tell the Background Worker to stop working.
My_BgWorker.CancelAsync();
}
}
}
but with no success. After doing CancelAsync(), a few minutes after, I can see the backgroundworker finishes and raise RunWorkerCompleted and I can see the task is completed checking e.Cancelled argument in the event but after this event is exectued the application continues without exiting and I have no idea what is doing....
I set WorkerSupportsCancellation to true to support cancel at the begining.
I would apreciate all answers. Thanks.
Cancellation is not automatic, your code in the DoWork event handler needs to handle the cancellation by checking the value of the CancellationPending property. Calling CancelAsync doesn't abort the thread, it merely sets CancellationPending to true...
For instance :
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
while(!bgw.CancellationPending)
{
...
}
}
I think Thomas Levesque pinpointed the issue.
On a general note: somewhere, some thread is still executing. You can try and find out what thread that is, by pausing the debug process (pause button, named "Break All"). At this point, the next code line executed should be highlighted. Also, you can use the Threads window (under Debug -> Windows) to see exactly which thread is still running, and where.
Perfect Thomas, setting ShutdownMode to OnMainWindowClose as you said solved my problem. Now debugger stops correctly ;) Thanks very much for helping me.
What I did is:
<Application
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
x:Class="GParts.App"
StartupUri="WinMain.xaml"
ShutdownMode="OnMainWindowClose">
<...>
</Application>
Finally I would like to do one thing respect to backgroundworker in DoWork event in case an exception is thrown by some type of error: I hanlde errors inside it with a try catch clause and into catch I do:
catch (Exception ex)
{
e.Result = ex.Message;
}
When backgroundworker finishes by an exception I want in RunWorkerCompleted to detect it with e.Error and show it. So what I do in RunWorkerCompleted is:
if (e.Cancelled)
{
// Cancelled
}
else if (e.Error != null)
{
// Exception Thrown
// Here I want to show the message that produced the exception in DoWork
// event. If I set e.Result = ex.Message in DoWork event, is e.Error here
// containing ex.Message?
}
else
{
// Completed);
}
Is e.Error in RunWorkerCompleted containing ex.Message?
Thanks.
I started a new WPF project in VS2008 and then added some code to trap DispatcherUnhandledException. Then I added a throw exception to Window1
but the error is not trapped by the handler. Why?
public App()
{
this.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(App_DispatcherUnhandledException);
}
void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
System.Windows.MessageBox.Show(string.Format("An error occured: {0}", e.Exception.Message), "Error");
e.Handled = true;
}
void Window1_MouseDown(object sender, MouseButtonEventArgs e)
{
throw new NotImplementedException();
}
This can happen because of the way you have the debugger handling exceptions -- Debug/Exceptions... should allow you to configure exactly how you want it handled.
Look at following msdn link http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx
Following is Relevant here
If an exception is not handled on either a background user interface (UI) thread (a thread with its own Dispatcher) or a background worker thread (a thread without a Dispatcher), the exception is not forwarded to the main UI thread. Consequently, DispatcherUnhandledException is not raised. In these circumstances, you will need to write code to do the following:
Handle exceptions on the background thread.
Dispatch those exceptions to the main UI thread.
Rethrow them on the main UI thread without handling them to allow DispatcherUnhandledException to be raised.
This is how I handle it. This isn't pretty but keep in mind that this type of error should never make it past debugging as a dev. Those errors should be long resolved before you go to production (so its okay that this isn't pretty). In the Startup project, in the App.xaml (App.xaml.cs) code behind, I put the following code.
OnStartup, create a DispatcherUnhandledException event handler
In the handler, use a MessageBox to display the message. Note that its likely the startup window has not yet been created so don't try to put it in a window.
e.Handle the error
I like to see when there are additional internal errors so I continue to call the display window until the internal error is null.
I'm not sure why the code block special characters aren't formatting this correctly. Sorry about that.
protected override void OnStartup(StartupEventArgs e)
{
// define application exception handler
Application.Current.DispatcherUnhandledException +=
AppDispatcherUnhandledException;
// defer other startup processing to base class
base.OnStartup(e);
}
private void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
runException(e.Exception);
e.Handled = true;
}
void runException(Exception ex)
{
MessageBox.Show(
String.Format(
"{0} Error: {1}\r\n\r\n{2}",
ex.Source, ex.Message, ex.StackTrace,
"Initialize Error",
MessageBoxButton.OK,
MessageBoxImage.Error));
if (ex.InnerException != null)
{
runException(ex.InnerException);
}
}
At first, even outside the debugging environment, my handler does not seem to be triggering.....then I realized I forget to set e.Handled = true.
In truth it was working but because e.Handled was still false the standard exception handler still kicked in and did its thing.
Once I set e.Handled = true, then everything was hunky dory. So if its not working for you, make sure you've done that step.
For those interested
It seems that the IDE is still breaking on exceptions and that if you click continue in the IDE it call the error handler.