Strange cross-threading UI errors - c#

I'm writing a WinForms app which has two modes: console or GUI. Three projects within the same solution, one for the console app, one for the UI forms and the third to hold the logic that the two interfaces will both connect too. The Console app runs absolutely smoothly.
A model which holds the user-selections, it has an IList<T> where T is a local object, Step, which implements INotifyPropertyChanged, so in the UI this is mounted on to a DataGridView. All is fine at runtime, the initial state of the objects is reflected on the screen.
Each of the Step objects is a task which is performed in turn; some of the properties will change, being reflected back to the IList and passed on to the DataGridView.
This action in the UI versions is done by creating a BackgroundWorker raising events back to the UI. The Step does it thing and generates a StepResult object which is an enumerated type indicating a result (e.g. Running, NotRun, OK, NotOK, Caveat) and a string to indicate a message (because the step ran but not quite as expected, i.e. with a Caveat). Normally the actions will involve a database interaction, but in debug mode I randomly generate a result.
If the message is null, there's never a problem, but if I generate a response like this:
StepResult returnvalue = new StepResult(stat, "completed with caveat")
I get an error saying that the DataGridView was being accessed from a thread other than the thread it was created on. (I'm passing this through a custom handler which should handle the invoking when required - maybe it doesn't?)
Then if I generate a unique response, e.g. using a random number r:
StepResult returnvalue = new StepResult(stat, r.ToString());
the actions succeed with no problem, the numbers are written cleanly to the DataGridView.
I'm baffled. I'm assuming it's somehow a string literal problem, but can anyone come up with a clearer explanation?

You've answered your own quesion:-
I get an error saying that the DataGridView was being accessed from a thread other than the thread it was created on.
WinForms insists that all actions performed on forms and controls are done in the context of the thread the form was created in. The reason for this is complex, but has a lot to do with the underlying Win32 API. For details, see the various entries on The Old New Thing blog.
What you need to do is use the InvokeRequired and Invoke methods to ensure that the controls are always accessed from the same thread (pseudocodeish):
object Form.SomeFunction (args)
{
if (InvokeRequired)
{
return Invoke (new delegate (Form.Somefunction), args);
}
else
{
return result_of_some_action;
}
}

Since you are doing UI binding via event subscription, you might find this helpful; it is an example I wrote a while ago that shows how to subclass BindingList<T> so that the notifications are marshalled to the UI thread automatically.
If there is no sync-context (i.e. console mode), then it reverts back to the simple direct invoke, so there is no overhead. When running in UI thread, note that this essentially uses Control.Invoke, which itself just runs the delegate directly if it is on the UI thread. So there is only any switch if the data is being edited from a non-UI thread - juts what we want ;-p

I found this article - "Updating IBindingList from different thread" - which pointed the finger of blame to the BindingList -
Because the BindingList is not setup for async operations, you must update the BindingList from the same thread that it was controlled on.
Explicitly passing the parent form as an ISynchronizeInvoke object and creating a wrapper for the BindingList<T> did the trick.

Related

Getting exception when using high-resolution timer to work in WPF [duplicate]

A common exception one can get when working with multiple threads in WPF is:
The calling thread cannot access this object because a different thread owns it
What are the options to deal with this properly?
Depending on the situation there are various options:
Accessing a control from another thread
e.g. updating a TextBlock with progress information.
Data Binding:
In this case the easiest thing you can do is avoiding the direct interaction with the control. You can just bind the property you want to access or modify to an object whose class implements INotifyPropertyChanged and then set the property on that object instead. The framework will handle the rest for you. (In general you rarely should need to interact with UI-elements directly, you can almost always bind the respective properties and work with the binding source instead; one case where direct control access may be necessary is control authoring.)
There are some cases where data binding alone is not enough, for example when trying to modify a bound ObservableCollection<T>, for this you need...
Dispatching:
You can dispatch your accessing code to the thread owning the object, this can be done by calling Invoke or BeginInvoke on the Dispatcher owning the object being accessed (getting this Dispatcher is possible on another thread).
e.g.
new Thread(ThisThreadStart).Start();
void ThisThreadStart()
{
textBlock.Dispatcher.Invoke(new Action(() => textBlock.Text = "Test"));
}
If it is not clear on which thread a method is executed you can use Dispatcher.CheckAccess to either dispatch or execute an action directly.
e.g.
void Update()
{
Action action = () => myTextBlock.Text = "Test";
var dispatcher = myTextBlock.Dispatcher;
if (dispatcher.CheckAccess())
action();
else
dispatcher.Invoke(action);
}
If an object is not a DispatcherObject and you still need the associated Dispatcher you can use Dispatcher.CurrentDispatcher in the thread creating the object (so doing this in the method being executed by a thread will not do you any good). For convenience as you usually create objects on the application's main UI thread; you can get that thread's Dispatcher from anywhere using Application.Current.Dispatcher.
Special cases:
BackgroundWorker
Move any control access to ProgressChanged as it occurs on the thread that created the instance (which should of course be the UI-thread)
Timers
In WPF you can use the DispatcherTimer for convenience, it does the dispatching for you so any code in Tick is invoked on the associated dispatcher. If you can delegate the dispatching to the data binding system you of course can use a normal timer as well.
You can read more about how the Dispatcher queue works and WPF threading in general on MSDN.
Accessing an object created on another thread
e.g. loading an image in the background.
If the object in question is not Freezable you should in general simply avoid creating it on another thread or restricting access to the creating thread. If it is Freezable you just need to call Freeze to make it accessible to other threads.
Accessing a data object from another thread
That is, the type whose instance is being updated is user-code. If an exception is thrown this situation probably came about by someone using DependencyObject as base type for a data class.
This situation is the same as accessing a control and the same approaches can be applied but usually it should be avoided in the first place. Granted, this allows for simple property change notifications via dependency properties and those properties can also be bound but often enough this is just not worth giving up thread-independency. You can get change notifications from INotifyPropertyChanged and the binding system in WPF is inherently asymmetrical, there always is a property that is bound (target) and something that is the source for this binding. Usually the UI is the target and the data is the source, meaning that only UI components should need dependency properties.
That would be several hundred lines of code, for something I "figured out".
But the summary is:
App_OnStartup
generate a background thread
in the callback,
Call
Application.Current.MainWindow.Dispatcher.CheckAccess() - gets the exception
Application.Current.Dispatcher.CheckAccess() does not
I have a udp listener object that communicates through events where the method/callbacks are +='ed in my mainWindow wpf .cs file.
The event handler functions are called with parameters, one being the message I want displayed in a listbox in the mainWindow.cs
Using the information in this thread by H.B. above;
I have added, tested and handled the crossthread in wpf in my eventhandler callback using the following code, but I use a real message not a hard coded one:
listBox1.Dispatcher.Invoke(new Action(() => listBox1.Items.Add("MessageHere")));
UPDATE:
This is better because you can put more things in the anonymous function.
listBox1.Dispatcher.Invoke((Action)delegate
{
listBox1.Items.Add(e.ReaderMessage);
});

Can't Access Variable Because It Is Owned By Another Thread [duplicate]

A common exception one can get when working with multiple threads in WPF is:
The calling thread cannot access this object because a different thread owns it
What are the options to deal with this properly?
Depending on the situation there are various options:
Accessing a control from another thread
e.g. updating a TextBlock with progress information.
Data Binding:
In this case the easiest thing you can do is avoiding the direct interaction with the control. You can just bind the property you want to access or modify to an object whose class implements INotifyPropertyChanged and then set the property on that object instead. The framework will handle the rest for you. (In general you rarely should need to interact with UI-elements directly, you can almost always bind the respective properties and work with the binding source instead; one case where direct control access may be necessary is control authoring.)
There are some cases where data binding alone is not enough, for example when trying to modify a bound ObservableCollection<T>, for this you need...
Dispatching:
You can dispatch your accessing code to the thread owning the object, this can be done by calling Invoke or BeginInvoke on the Dispatcher owning the object being accessed (getting this Dispatcher is possible on another thread).
e.g.
new Thread(ThisThreadStart).Start();
void ThisThreadStart()
{
textBlock.Dispatcher.Invoke(new Action(() => textBlock.Text = "Test"));
}
If it is not clear on which thread a method is executed you can use Dispatcher.CheckAccess to either dispatch or execute an action directly.
e.g.
void Update()
{
Action action = () => myTextBlock.Text = "Test";
var dispatcher = myTextBlock.Dispatcher;
if (dispatcher.CheckAccess())
action();
else
dispatcher.Invoke(action);
}
If an object is not a DispatcherObject and you still need the associated Dispatcher you can use Dispatcher.CurrentDispatcher in the thread creating the object (so doing this in the method being executed by a thread will not do you any good). For convenience as you usually create objects on the application's main UI thread; you can get that thread's Dispatcher from anywhere using Application.Current.Dispatcher.
Special cases:
BackgroundWorker
Move any control access to ProgressChanged as it occurs on the thread that created the instance (which should of course be the UI-thread)
Timers
In WPF you can use the DispatcherTimer for convenience, it does the dispatching for you so any code in Tick is invoked on the associated dispatcher. If you can delegate the dispatching to the data binding system you of course can use a normal timer as well.
You can read more about how the Dispatcher queue works and WPF threading in general on MSDN.
Accessing an object created on another thread
e.g. loading an image in the background.
If the object in question is not Freezable you should in general simply avoid creating it on another thread or restricting access to the creating thread. If it is Freezable you just need to call Freeze to make it accessible to other threads.
Accessing a data object from another thread
That is, the type whose instance is being updated is user-code. If an exception is thrown this situation probably came about by someone using DependencyObject as base type for a data class.
This situation is the same as accessing a control and the same approaches can be applied but usually it should be avoided in the first place. Granted, this allows for simple property change notifications via dependency properties and those properties can also be bound but often enough this is just not worth giving up thread-independency. You can get change notifications from INotifyPropertyChanged and the binding system in WPF is inherently asymmetrical, there always is a property that is bound (target) and something that is the source for this binding. Usually the UI is the target and the data is the source, meaning that only UI components should need dependency properties.
That would be several hundred lines of code, for something I "figured out".
But the summary is:
App_OnStartup
generate a background thread
in the callback,
Call
Application.Current.MainWindow.Dispatcher.CheckAccess() - gets the exception
Application.Current.Dispatcher.CheckAccess() does not
I have a udp listener object that communicates through events where the method/callbacks are +='ed in my mainWindow wpf .cs file.
The event handler functions are called with parameters, one being the message I want displayed in a listbox in the mainWindow.cs
Using the information in this thread by H.B. above;
I have added, tested and handled the crossthread in wpf in my eventhandler callback using the following code, but I use a real message not a hard coded one:
listBox1.Dispatcher.Invoke(new Action(() => listBox1.Items.Add("MessageHere")));
UPDATE:
This is better because you can put more things in the anonymous function.
listBox1.Dispatcher.Invoke((Action)delegate
{
listBox1.Items.Add(e.ReaderMessage);
});

Should I Invoke or change my Get/Set Method? "InvalidOperationException" C#

I get an InvalidOperationException with the message,
Control control name accessed from a thread other than the thread it was created on.
The "Control" was created by a Thread that is no longer doing any work, and I don't know how if I can invoke the method or if I should create a local variable that contains the value of the tags_richtextbox.
The class that is Giving the error:
public class details_Panel
{
public string tags
{
get { return tags_richtextbox.Text; }
set { tags_richtextbox.Text = value; }
}
private RichTextBox tags_richtextbox = new RichTextBox() { DetectUrls = false, Dock = System.Windows.Forms.DockStyle.Fill, ReadOnly = true };
}
The Function Giving the error:
detailsPanelSaveData.tags.AddRange(ent.detailspanel.tags.Split(','));
So should I Invoke or add a private variable that has the same value as tags_richtextbox.Text and if I should invoke, whats the syntax to do that and wait for it to finish? (I'm still learning about threading and figuring out the correct invoke syntax)
Edit: DetailPanelSaveData.tags is a List<string> Just realized I wasn't very clear
So to Clarify I'm trying to save a split string in a list of strings.
The "Control" was created by a Thread that is no longer doing any work
Without a good, minimal, complete code example that reliably reproduces the problem, it's impossible to completely understand the problem. However, the idea of there being a thread in which some instance of a control was created, and yet that thread "is no longer doing any work" is a bit weird, to say the least.
Control objects must only be created in a thread that is running the UI. In most programs, there is only one such thread and there should only ever be one such thread. If you have code running in a different thread, and due to some operation in that thread there is a point at which a control needs to be created, you need to transfer execution to that one UI thread for the purpose of creating the control, so that the control is created in the correct thread.
Without a better code example, it's not clear what else you need to fix. But for sure, you need to change the code where that control is created so that you're creating the control in the UI thread.
Elsewhere, e.g. when you are converting the text into an array of tags to add to your list, you may also need to transfer execution to the UI thread when you access the tags property where the tags_richtextbox object is accessed. Or maybe you won't. That all depends on where that code is executing; if it's in the UI thread, then you're all set. Otherwise, yes…you need to wrap the operation in some kind of cross-thread invocation.
NOTE: nowhere in your question are you specific about which GUI API in .NET you are using. Judging from the little bit of code and your comments in the question, I'm guessing this is Winforms. But WPF and Winrt (Store apps) have the same issue, and so the above advice applies equally in all scenarios. Of course, the exact technique for transferring execution to the UI thread varies according to API. Winforms uses Control.Invoke(), WPF uses Dispatcher.Invoke(), and Winrt uses Dispatcher.RunAsync(). It is these methods (or their asynchronous equivalents, in the case of Winforms or WPF) to which I am referring when I describe a "cross-thread invocation" or the need to "transfer execution to the UI thread".
NOTE: there is one exception to some of the above, which I hesitate to even mention because I doubt it applies in your scenario, and even if it does, the first thing you should do is fix your code so it doesn't. But for completeness, I am compelled to mention that a program can have more than UI thread running at a time. This is rare and should be avoided, but it can happen. If it does, then it is possible that one control object could be created in a thread that is legitimately different from that which owns some other control object. Now, in that case it would be your responsibility to ensure that any given UI thread continues to run for as long as any of the objects it owns still exist, and you will still need to use the GUI API's mechanism for transferring execution to a different thread when that object is accessed by a thread other than the one which owns it. But that is a way that, even though still not correct, you could wind up with a control object that was created by a UI thread that "is no longer doing any work".

MultiThreading COMObject and UI Thread (C#)

This is my first post here as actually i usually solve all my issue with the awesome
post database you can find here. But I'm actually stuck right now:
I'm working on a project following the MVVM including a COM object.
As I read during my research, I understand that the COM object is only accessible from the thread which created it. My COM object implements the following interface
interface IComUpdate
{
void Update();
}
So when I create my COM object, each time there is an update (I dont know when, its random) the COM Server will call the Update() of the COM object class I did implement.
My goal was to create a different thread, naming a COM object thread, where the COM object exist independantly of my UI Thread, so everytime there is an update, I handle it in a different thread than the UI Thread.
Actually it is working:
At the Beginning of my ViewModel I create a collection of a specific object.
This object, lets call it ModelObj, is part of the model and defines a static constructor in which the application, apart from initializing some variables, creates and starts a new thread for the COM object:
Thread t = new System.Threading.Thread(() =>
{
System.Threading.Thread.CurrentThread.Name = "Thread of COM Object";
IComUpdate myComObj;
myComObj = (IComUpdate)Activator.CreateInstance(blabla);
Application.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
It actually works very well, in the Update() implementation of my COM object, I actually see that the thread is the one just created and not the UI thread.
Now the issue is this: this ModelObj I create implements the INotifyPropertyChanged interface.
My thinking was the following: each time the COM object receives an update, I handle data from the COM object thread, and update some property of my ModelObjinstance from this thread, so these properties will then raise the property change of my ModelObj and the UI thread will update the User Interface.
If the UI update takes too much time, I might miss some Update() to appear on the screen but the COM object will have them recorded in my ModelObj instance so it is not very important that the UI catch all the updates, I just didnt want the COM object to have to wait for the UI to be updated to be called again.
I read tons of posts and thought then that my RaisePropertyChanged("property") would fail.
Actually even in the COM object's thread, the RaisePropertyChanged successfully executes, so tracing my code, I see it switches to my ViewModel assembly where I do
// Here I'm still in the thread of my COM object!
base.NotifyOfPropertyChange<string>(() => this.property)
and then the UI Update.
Note: I'm using Caliburn Micro for binding between my View in WPF and my ViewModel.
So I can't trace after this base.NotifyOfPropertyChange<string>(() => this.property). Maybe Caliburn handles the thread switch, this is not really my issue.
What I can say is that my COM object thread waits for the UI to update to get to the next instruction after my RaisePropertyChanged("property"), so it's exactly the same as if the UI thread did the whole work.
I want my COM object thread to update my ModelObj which will send to send the UI a message to update (because some fields of this ModelObj have changed) and continue immediatly, without knowing if the UI actually updates or not.
Does someone got an idea about this behaviour?
Thank you very much.
####UPDATE####
Thanks everyone for such quick answers.
I did actually as Zdeslav Vojkovic suggested :
You should always update GUI from GUI thread
For completeness here is how I did:
Because my View is full WPF with no code behind i dont have any controls or form to be call BeginInvoke from, so in the static constructor of my ModelObj, I built an invisible Control from the UI Thread just to be able to call BeginInvoke on it.
So i declared it :
public static Control mInvokeControl;
delegate void MyDelegate();
private MyDelegate _NotifyDelegate;
and then did this in the static constructor of my Object:
mInvokeControl = new Control();
mInvokeControl.CreateControl();
in the normal constructor i Initialize the delegate this way:
_NotifyDelegate = new MyDelegate(this.NotifyByInvoke);
Then after i just use it this way:
ModelObj.mInvokeControl.BeginInvoke(this._NotifyDelegate );
With the method being:
public void NotifyByInvoke()
{
RaisePropertyChanged("Update");
}
Everything works fine !
the COMObj is only accessible from the thread which created it
this is not true. It depends on objects apartment model, but usually you can access it from any thread and it will be either called on same thread or marshaled to proper thread.
I belive that your problem is that you update GUI from background thread which is a major no-no. You should always update GUI from GUI thread. When you update your model object, it still happens on background thread and event of INotifyPropertyChanged interfaces fires on that thread.
You need to synchronize model update to GUI thread by using something like this (WinForms, not WPF - in WPF you should use frm.Dispatcher.BeginInvoke but the problem is the same):
private delegate void ExecuteActionHandler(Action action);
public static void ExecuteOnUiThread(this Form form, Action action)
{
if (form.InvokeRequired) { // we are not on UI thread
// Invoke or BeginInvoke, depending on what you need
// but you said ' and continue immediatly' so BeginInvoke it is
form.BeginInvoke(new ExecuteActionHandler(ExecuteOnUiThread), action);
}
else { // we are on UI thread so just execute the action
action();
}
}
There is another question with similar problem and I have provided additional details there.
I do not know how much data you process, or how much time it takes to perform the GUI part. You may also consider to use locked queues. You can use a queue within your ModelObj to enqueue new tasks by it. This you do with everything you get. Then you may have a timer thread (on the GUI thread).
Here you just check the locked queue, whether there is some new data to display on the GUI. You may dequeue the full list here locally. Then you can also check, whether there is more than one data to display on one component. This way you can skip updates, where you already have newer updates.
And you skip the time for invoking the gui thread to perform the action. You can do several GUI updates at once. If you have too much things to do, you may dequeue only up to a specific number of items to let the GUI react on user interactions. However, you need to check that the queue is not constantly growing.

C# GUI Application, Another class from another thread updating the UI

I've been researching on how to do this for about a week and I'm still not sure about the correct approach, in some examples I see the Thread class is used in others I see Invoke is used which has confused me a bid.
I have a GUI program in c# which contains a textBox which will be used to give information to the user.
The problem I'm facing is that I'm not sure how I can append text to textBox from another class which is running on another thread. If someone can show me a working example, it would help me greatly.
Best Regards!
Easy:
MainWindow.myInstance.Dispatcher.BeginInvoke(new Action(delegate() {MainWindow.myInstance.myTextBox.Text = "some text";});
WHERE MainWindow.myInstance is a public static variable set to the an instance of MainWindow (should be set in the constructor and will be null until an instance is constructed).
Ok thats a lot in one line let me go over it:
When you want to update a UI control you, as you say, have to do it from the UI thread. There is built in way to pass a delegate (a method) to the UI thread: the Dispatcher. I used MainWindow.myInstance which (as all UI components) contains reference to the Dispatcher - you could alternatively save a reference to the Dispatcher in your own variable:
Dispatcher uiDispatcher = MainWindow.myInstance.Dispatcher;
Once you have the Dispatcher you can either Invoke() of BeginInvoke() passing a delegate to be run on the UI thread. The only difference is Invoke() will only return once the delegate has been run (i.e. in your case the TextBox's Text has been set) whereas BeginInvoke() will return immediately so your other thread you are calling from can continue (the Dispatcher will run your delegate soon as it can which will probably be straight away anyway).
I passed an anonymous delegate above:
delegate() {myTextBox.Text = "some text";}
The bit between the {} is the method block. This is called anonymous because only one is created and it doesnt have a name - but I could instantiated a delegate:
Action myDelegate = new Action(UpdateTextMethod);
void UpdateTextMethod()
{
myTextBox.Text = "new text";
}
Then passed that:
uiDispatcher.Invoke(myDelegate);
I also used the Action class which is a built in delegate but you could have created your own - you can read up more about delegates on MSDN as this is going a bit off topic..
Sounds like you're using a background thread for processing, but want to keep the UI responsive? The BackgroundWorker sounds like the ticket:
The BackgroundWorker class allows you
to run an operation on a separate,
dedicated thread. Time-consuming
operations like downloads and database
transactions can cause your user
interface (UI) to seem as though it
has stopped responding while they are
running. When you want a responsive UI
and you are faced with long delays
associated with such operations, the
BackgroundWorker class provides a
convenient solution.
Just use BackgroundWorker for the same. It is simple and takes away the pain of managing threads of your own. for more, you can see: http://dotnetperls.com/backgroundworker

Categories