Cross threading exception when trying to access object from another thread , wpf , c# - wpf

I have a wpf application.
During the running of the application, when I get to some method I fire event which performs some operations . In this event I have to access to an instance of DLL that works with Database , and it throws exception which tells that another thread owns that object. What would be the best way to handle this?
//this is in the main thread - in MainWindow.cs - code behind
MyDataBaseManager DB_manager = new MyDataBaseManager(connectionString);
//event handler
void MainWindow_MyCustomEvent(object sender, MainWindow.MyCustomEventArgs e)
{
try
{
if (str1 == str2)
{
//getting exception when trying to perform this statement
DB_manager.UpdateTable(this.textBlock_MyTextBlock.Text, DateTime.Now, currenrUser);
theNextstring = DB_manager.GetTheNextString();
if (theNextstring != string.Empty)
{
this.textBlock_theNextstring.Text = theNextstring×£
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButton.OKCancel, MessageBoxImage.Error);
}
}
when I compare two strings in the if statement, It doesn't throw an exception , but when I want to use DB_manager or to use the UI components , I get the -
The calling thread cannot access this object because a different thread owns it.
Should I pass to the event a connection string and make a new instance in the object? Or there is another , better solution?
thanks...

the best way to do it is to use the Dispatcher.Invoke method ...
this.textBlock_theNextstring.Dispatcher.Invoke.
Sample -
http://social.msdn.microsoft.com/forums/en-US/wpf/thread/360540eb-d756-4434-86f9-a3449f05eb55

Related

WPF : Dispatcher processing has been suspended, but messages are still being processed

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.

WPF - Catch exceptions in code executed by SimpleMVVM messagebus

I'm building a WPF application using the SimpleMVVM framework and I'm having trouble catching exceptions. I use the MessageBus of SimpleMVVM to send a message to another viewmodel. This all works fine, but I noticed that exceptions raised in the code executed by the messagebus get suppressed. Here's what I've got so far:
My MainWindow contains a button that fires a TempCommand on the MainWindowViewModel. This command in turn calls the Test method (shown below), which sends out a notification message using the MessageBus of SimpleMVVM.
private void Temp()
{
SendMessage("Temp", new NotificationEventArgs());
}
My MainWindow also contains a Frame with content. The ViewModel of this content, CustomerViewModel, has registered to receive these notifications in its constructor:
public CustomerDetailsViewModel(ICustomerServiceAgent agent)
{
RegisterToReceiveMessages("Temp", Temp);
}
Where the Temp method simply throws an exception:
private void Temp(object sender, NotificationEventArgs args)
{
throw new NotImplementedException("Somewhere, something horrible happened");
}
When I debug the application, I clearly see the Temp method being called and the exception being raised. But for some reason, that's all. The application is unaffected and my exception trapping code is unaware of the exception.
I trap exceptions in two ways. The first is by handling the event on the Dispatcher:
<Application x:Class="MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
DispatcherUnhandledException="App_DispatcherUnhandledException">
Where the code-behind looks like:
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
Log("Exception: " + e.Exception.Message);
e.Handled = true;
}
public static void Log(string message)
{
File.AppendAllText(#"D:\Temp\log.txt", "[" + DateTime.Now.ToString("F") + "] [" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() + "] " + message + Environment.NewLine);
}
This code catches some exceptions, but not all. I found out that WPF suppresses databinding exceptions by default. Because my ViewModels are bounded through the DataContext property on my view, I thought this was the problem. I found this article, which defines a TraceListener that uses the PresentationTraceSources class. Databinding exceptions now get caught, but... Not the exceptions thrown in the code executed through the MessageBus.
I've created a solution demonstrating this behavior, it can be downloaded here.
And this is where I'm stuck. What am I missing? How do I catch these exceptions?
Big thanks in advance.
JP
I think it is a bug or problem with the implementation of the MessageBus in SimpleMVVM.
Cause multiple subscribers can subscribe to a token, the current implementation ensures that each subscribed method gets called even when one registered method throws an exception. In this case the exception is catched and written out to the Console.
The method that is responsible to call a subscribed method is SafeNotify
private void SafeNotify(Action method, bool post) {
try {
// Fire the event on the UI thread
if (post){
if (Dispatcher.CheckAccess()){
method();
}
else{
Dispatcher.BeginInvoke(method);
}
}
// Fire event on a ThreadPool thread
else{
ThreadPool.QueueUserWorkItem(o => method(), null);
}
}
catch (Exception ex){
// If there's an exception write it to the Output window
Debug.WriteLine(ex.ToString());
}
}
When the method call gets queued in the ThreadPool, you have no chance to handle the thrown exception. See also this post for further information.
The only option you have is to ensure that the code of your own registered methods is always surrounded by a try-catch-block.

Throw new Exception and Application_UnhandledException

My Scenario:
I'm using a Silverlight MVVM pattern. All my view models inherit from a BaseViewModel class that maintains some basic values and behaviours.
One of these behaviours determines if the user is authorised to use particular functionality and returns a boolean.
If the function is not located, I want to throw a new exception and catch this in the App.xaml Application_UnhandledException method, and raise my own exception event, something like this:
protected bool IsFunctionEnabled(string FunctionName)
{
//fetch the function / role
if (_FunctionRoles().ContainsValue(FunctionName))
{
KeyValuePair<int, string> kvp = _FunctionRoles().GetEntryByStringValue(FunctionName);
//determine if the user has been assigned to this role
return (_UserRoles().ContainsKey(kvp.Key));
}
//throw an exception when the function name is not located.
throw new Exception(string.Format(Constants.UNHANDLED_EXCEPTION, "security role assignment: '" + FunctionName + "' not located."));
}
I then want this automatically picked up in App.XAML:
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
// throw this message to the main application exception event handler
ApplicationEvents.OnExceptionOccurred(this,
new ExceptionEventArgs(e.ExceptionObject,
null,
ExceptionImportance.Critical));
}
My Problem
When the exception is thrown, it is not getting bubbled up the stack. When debugging the exception is hit over and over again, no other code is getting run.
What am I doing wrong here?
Thanks,
Mark
I think this is occurring because the exception is getting thrown outside of the UI thread, so there is no other code "waiting to run". Triggering an event here means writing a lot more code, but does allow the UI thread to subscribe to this and render a message in the UI properly.

Invoke or BeginInvoke cannot be called on a control until the window handle has been created

I have a SafeInvoke Control extension method similar to the one Greg D discusses here (minus the IsHandleCreated check).
I am calling it from a System.Windows.Forms.Form as follows:
public void Show(string text) {
label.SafeInvoke(()=>label.Text = text);
this.Show();
this.Refresh();
}
Sometimes (this call can come from a variety of threads) this results in the following error:
System.InvalidOperationException occurred
Message= "Invoke or BeginInvoke cannot be called on a control until the window handle has been created."
Source= "System.Windows.Forms"
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.Invoke(Delegate method)
at DriverInterface2.UI.WinForms.Dialogs.FormExtensions.SafeInvoke[T](T control, Action`1 action)
in C:\code\DriverInterface2\DriverInterface2.UI.WinForms\Dialogs\FormExtensions.cs:line 16
What is going on and how do I fix it? I know as much as it is not a problem of form creation, since sometimes it will work once and fail the next time so what could the problem be?
PS. I really really am awful at WinForms, does anyone know a good series of articles that explains the whole model and how to work with it?
It's possible that you're creating your controls on the wrong thread. Consider the following documentation from MSDN:
This means that InvokeRequired can
return false if Invoke is not required
(the call occurs on the same thread),
or if the control was created on a
different thread but the control's
handle has not yet been created.
In the case where the control's handle
has not yet been created, you should
not simply call properties, methods,
or events on the control. This might
cause the control's handle to be
created on the background thread,
isolating the control on a thread
without a message pump and making the
application unstable.
You can protect against this case by
also checking the value of
IsHandleCreated when InvokeRequired
returns false on a background thread.
If the control handle has not yet been
created, you must wait until it has
been created before calling Invoke or
BeginInvoke. Typically, this happens
only if a background thread is created
in the constructor of the primary form
for the application (as in
Application.Run(new MainForm()),
before the form has been shown or
Application.Run has been called.
Let's see what this means for you. (This would be easier to reason about if we saw your implementation of SafeInvoke also)
Assuming your implementation is identical to the referenced one with the exception of the check against IsHandleCreated, let's follow the logic:
public static void SafeInvoke(this Control uiElement, Action updater, bool forceSynchronous)
{
if (uiElement == null)
{
throw new ArgumentNullException("uiElement");
}
if (uiElement.InvokeRequired)
{
if (forceSynchronous)
{
uiElement.Invoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
}
else
{
uiElement.BeginInvoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
}
}
else
{
if (uiElement.IsDisposed)
{
throw new ObjectDisposedException("Control is already disposed.");
}
updater();
}
}
Consider the case where we're calling SafeInvoke from the non-gui thread for a control whose handle has not been created.
uiElement is not null, so we check uiElement.InvokeRequired. Per the MSDN docs (bolded) InvokeRequired will return false because, even though it was created on a different thread, the handle hasn't been created! This sends us to the else condition where we check IsDisposed or immediately proceed to call the submitted action... from the background thread!
At this point, all bets are off re: that control because its handle has been created on a thread that doesn't have a message pump for it, as mentioned in the second paragraph. Perhaps this is the case you're encountering?
I found the InvokeRequired not reliable, so I simply use
if (!this.IsHandleCreated)
{
this.CreateHandle();
}
Here is my answer to a similar question:
I think (not yet entirely sure) that
this is because InvokeRequired will
always return false if the control has
not yet been loaded/shown. I have done
a workaround which seems to work for
the moment, which is to simple
reference the handle of the associated
control in its creator, like so:
var x = this.Handle;
(See
http://ikriv.com/en/prog/info/dotnet/MysteriousHang.html)
The method in the post you link to calls Invoke/BeginInvoke before checking if the control's handle has been created in the case where it's being called from a thread that didn't create the control.
So you'll get the exception when your method is called from a thread other than the one that created the control. This can happen from remoting events or queued work user items...
EDIT
If you check InvokeRequired and HandleCreated before calling invoke you shouldn't get that exception.
If you're going to use a Control from another thread before showing or doing other things with the Control, consider forcing the creation of its handle within the constructor. This is done using the CreateHandle function.
In a multi-threaded project, where the "controller" logic isn't in a WinForm, this function is instrumental in Control constructors for avoiding this error.
Add this before you call method invoke:
while (!this.IsHandleCreated)
System.Threading.Thread.Sleep(100)
Reference the handle of the associated control in its creator, like so:
Note: Be wary of this solution.If a control has a handle it is much slower to do things like set the size and location of it. This makes InitializeComponent much slower. A better solution is to not background anything before the control has a handle.
var that = this; // this is a form
(new Thread(()=> {
var action= new Action(() => {
something
}));
if(!that.IsDisposed)
{
if(that.IsHandleCreated)
{
//if (that.InvokeRequired)
that.BeginInvoke(action);
//else
// action.Invoke();
}
else
that.HandleCreated+=(sender,event) => {
action.Invoke();
};
}
})).Start();
I had this problem with this kind of simple form:
public partial class MyForm : Form
{
public MyForm()
{
Load += new EventHandler(Form1_Load);
}
private void Form1_Load(Object sender, EventArgs e)
{
InitializeComponent();
}
internal void UpdateLabel(string s)
{
Invoke(new Action(() => { label1.Text = s; }));
}
}
Then for n other async threads I was using new MyForm().UpdateLabel(text) to try and call the UI thread, but the constructor gives no handle to the UI thread instance, so other threads get other instance handles, which are either Object reference not set to an instance of an object or Invoke or BeginInvoke cannot be called on a control until the window handle has been created. To solve this I used a static object to hold the UI handle:
public partial class MyForm : Form
{
private static MyForm _mf;
public MyForm()
{
Load += new EventHandler(Form1_Load);
}
private void Form1_Load(Object sender, EventArgs e)
{
InitializeComponent();
_mf = this;
}
internal void UpdateLabel(string s)
{
_mf.Invoke((MethodInvoker) delegate { _mf.label1.Text = s; });
}
}
I guess it's working fine, so far...
What about this :
public static bool SafeInvoke( this Control control, MethodInvoker method )
{
if( control != null && ! control.IsDisposed && control.IsHandleCreated && control.FindForm().IsHandleCreated )
{
if( control.InvokeRequired )
{
control.Invoke( method );
}
else
{
method();
}
return true;
}
else return false;
}

Winforms threading problem, second thread can't access 1st main forms controls

I have a winforms application, the issue has to do with threading.
Since I am calling 'MyCustomCode() which creates a new thread, and calls the method
'SomeMethod()' which then accesses MessageBox.Show(...).
The problem has to do with threading, since the newly created thread is trying to access
a control that was created on another thread.
I am getting the error:
Cross-thread operation not valid: Control 'TestForm' accessed from a thread other than the thread it was created on.
public TestForm()
{
InitializeComponent();
// custom code
//
MyCustomCode();
}
public void SomeMethod()
{
// ***** This causes an error ****
MessageBox.Show(this,
ex.Message,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
private void InitializeAutoUpdater()
{
// Seperate thread is spun to keep polling for updates
ThreadStart ts = new ThreadStart(SomeMethod);
pollThread = new Thread(ts);
pollThread.Start();
}
Update
If you look at this example http://www.codeproject.com/KB/cs/vanillaupdaterblock.aspx, the method CheckAndUpdate is calling MessageBox.Show(..) that is what my problem is. I would have thought that code was good to go!
Funny thing is that this code was working just fine on Friday???
You cannot acces UI elements from multiple threads.
One way to solve this is to call the Invoke method of a control with a delegate to the function wich use the UI elements (like the message box). Somethin like:
public delegate void InvokeDelegate();
public void SomeMethod()
{
button1.Invoke((InvokeDelegate)doUIStuff);
}
void doUIStuff()
{
MessageBox.Show(this,
ex.Message,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
to avoid cross-thread exceptions (InvalidOperationException), here is the code pattern:
protected delegate void someGuiFunctionDelegate(int iParam);
protected void someGuiFunction(int iParam)
{
if (this.InvokeRequired)
{
someGuiFunctionDelegate dlg = new
someGuiFunctionDelegate(this.someGuiFunction);
this.Invoke(dlg, new object[] { iParam });
return;
}
//do something with the GUI control here
}
i agree that this is annoying, but it is an artifact of the fact that windows GUI controls are not thread-safe. The exception can be turned off with a flag somewhere or other, but don't do that as it can lead to extremely hard to find bugs.
To keep things simple you can look into using the BackGroundWorker class. This class will provide a framework for to handle your threading and progress notification events. Your ui thread will handle the progress event and display the error message you pass back.
Use Control.BeginInvoke or Control.Invoke methods
OR
Use SynchronizationContext
I know this is an older post, but I recently found an elegant solution to this problem using generics and extension methods. This is a combination of the authors works and some comments.
A Generic Method for Cross-thread Winforms Access
http://www.codeproject.com/KB/cs/GenericCrossThread.aspx
public static void Manipulate<T>(this T control, Action<T> action) where T : Control
{
if (control.InvokeRequired)
{
control.Invoke(new Action<T, Action<T>>(Manipulate),
new object[] { control, action });
}
else
{ action(control); }
}
This can be called in the following manner, for simplicity I used a label.
someLabel.Manipulate(lbl => lbl.Text = "Something");
You should NOT use BeginInvoke, you should use Invoke, then once you grasp that, you can look into using BeginInvoke if really needed.
Check for InvokeRequired
I praticularly like a recursive call.
public delegate void InvokeDelegate(string errMessage);
public void SomeMethod()
{
doUIStuff("my error message");
}
void doUIStuff(string errMessage)
{
if (button1.InvokeRequired)
button1.Invoke((InvokeDelegate)doUIStuff(errMessage));
else
{
MessageBox.Show(this,
ex.Message,
errMessage,
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
}
'*******************************************************************
' Get a new processor and fire it off on a new thread.
'*******************************************************************
fpProc = New Processor(confTable, paramFile, keyCount)
AddHandler fpProc.LogEntry, AddressOf LogEntry_Handler
Dim myThread As System.Threading.Thread = New System.Threading.Thread(AddressOf fpProc.ProcessEntry)
myThread.Start()
Then in the parent app you have:
'*************************************************************************
' Sub: LogEntry_Handler()
' Author: Ron Savage
' Date: 08/29/2007
'
' This routine handles the LogEntry events raised by the Processor class
' running in a thread.
'*************************************************************************
Private Sub LogEntry_Handler(ByVal logLevel As Integer, ByVal logMsg As String) Handles fProc.LogEntry
writeLogMessage(logMsg);
End Sub
That's what I do.

Resources