In a WPF application I had a BackgroundWorker thread creating an object. Let's call the object foo.
Background worker code:
SomeClass foo = new SomeClass();
// Do some operation on foo
// Set some dependency property on the main class to foo
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(SendOrPostCallback)delegate { SetValue(FooProperty, foo); },
foo);
Now, when the main class tries to access FooProperty using a getter, I get an InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
If the thread the create the object is finished, why does it still own the object? Is there someway around this.?
An object you create in a given thread is owned by that thread. That's why you're getting an InvalidOperationException. If you would like to set a property in a background thread, I recommend having the delegate return the desired value and calling SetValue from your main thread. (thread that created the object).
The vast majority of objects in WPF have thread affinity. That is once created on a particular thread, a WPF object will then only operate when used from that thread. This restriction is enforced (unlike WinForms) on practically every operation you do on that object.
You will need to change your code to have Foo created on the actual UI thread for this scenario.
Assuming SomeClass is derived from DispatcherObject, the thread that created it runs the message pump that is responsible for processing messages for the foo object. Therefore if that thread ends then the object can no longer process messages, which isn't a good idea.
In most situations you should use the same UI thread to create all of your UI objects (or anything else that is derived from DispatcherObject and make sure it runs for the duration of your application. Then use the Dispatcher to send messages to it from your worker threads.
Related
I want to create an instance of an object from an assembly that implements an interface I define in my Forms app. I would create this object at app startup using Activator.CreateInstance, and keep an application-level reference to it.
At certain points during this application I want to call methods on this object without holding up the main thread using Task.Run(() => IMyObject.DoSomeWork(someList, someList2)). I just want to make a "fire and forget" void method call and I don't need to await or even register callbacks.
Will the fact that the app is running in an STA thread pose an issue? Do I have to worry about leaks or premature collection of objects I instantiate on the main thread and reference inside the task closure? I only intend to read the contents of these lists, not modify them.
No need to worry; as soon as you create the delegate, all the objects it references will be kept in memory, at least until the Task.Run exits. There's nothing that an STA thread does that changes that.
Threads don't factor into GC at all - except that all stacks for running threads contain root objects. You can cross-reference objects however you want and it won't confuse the GC.
This method call sits inside a class derived from DispatcherObject:
Dispatcher.Invoke(DispatcherPriority.Input, new ThreadStart(() =>
{
var exported = formatProvider.Export(original.Workbook);
Workbook = formatProvider.Import(exported);
}));
The method on the class is called by a backgroundworker in its DoWork delegate.
Workbook is Telerik's Workbook, as used by the RadSpreadsheetControl. Obviously, workbooks can only be accessed by the UI thread.
The above code throws an InvalidOperationException, saying
The calling thread must be STA, because many UI components require
this.
I don't really understand, as I thought that when invoking the actions with a Dispatcher, I would be calling it from the UI Thread, which is STA?
What am I missing here and how can this be fixed? Or should this work in general and the bug is somewhere else? What could be a reason then?
TL;DR: You must create this DispatcherObject inside your UI thread, not in a worker.
DispatcherObject.Dispatcher, which you are marshalling the operation to, is set to Dispatcher.CurrentDispatcher at the time of the object's construction. If the object is not created inside your existing UI thread then the documented behavior of CurrentDispatcher is to create a new dispatcher object associated with the thread. Later on, Invoke tries to marshal the call to that thread (which is not STA) resulting in the error.
It is not sufficient to use a class derived from DispatcherObject. You must use the Dispatcher from an existing UIElement created from XAML (or at least make sure, you create your class from inside the GUI thread where it picks the right Dispatcher).
I have to use functionality that is in another application domain. The result should be displayed in user control.
I have something like that:
var instance = domain.CreateInstanceFromAndUnwrap(...);
instance.Foo(myWpfUserControl as ICallback);
Foo(ICallback itf) {
itf.SetData("...");
}
WpfUserControl.SetData(string data)
{
if (!Dispatcher.CheckAccess())
Dispatcher.Invoke(...)
...
}
I had to put [Serializable] attribute onto WpfUserControll class and implement serialization contructor as well as ISerializable interface but now i receive exception:
The calling thread must be STA because many UI components require this
that is raised from UserControl() constructor
What shall I do to avoid this ?
Thank you in advance !
==============================
Solution
as #Al noticed, my user control have to be serialized when it comes to cross-application-domain calls. Now i pass proxy, that implements ICallback interface. Proxy was marked with Serializable attribute.
Proxy implementation should have absolutely no knowledge about user control as there should be an attempt to deserialize user control instance once again. When I tried to abstract proxy from user control via interface it didn't help. When i tried to pass interface to proxy (that was implemented by user control) - same exception occured.
Finally I decoupled proxy and user control with queue/semaphor. Queue was monitored by a worker thread that deligated calls to user control
p.s. this queue should be inherited from "MarshalByObjectRef".
If the exception is coming from the constructor, it means that you're not creating this control instance from the UI thread. This can be fine but you have to make sure the Thread is an STA thread by calling .SetApartmentState(ApartmentState.STA) on the thread object before the thread is started.
This also means you have to have access to the thread object before its started so you cant do this on a threadpool thread.
The best way to avoid the problem though is probably to create the control on the main UI thread and then assign the Text value using the Dispatcher (or a Task on the UiScheduler). That way you'll also avoid problems if the main thread needs to set, get or bind to the control, as that would cause a cross thread exception if the control was created on another thread
i'd advice against seriealizing the control this way if possible. doing that will generate a new object that is not attatched to any panels or some such, and the original control would not be updated. sadly you cant inheirit from MarshalByRefObject that would eliminate serialization since it would only pass a reference to the other domain.
If you can, call Foo separately and then pass the result to SetData in the original Appdomain
I have a form and several external classes (serial port, file access) that are instantiated by the form.
1) What's the simplest way to run an instance of an external class in its own thread?
2) Is the instance's thread automatically terminated when the form closes?
1) What's the simplest way to run an instance of an external class in its own thread?
Instances of classes do not "run". Methods do.
As such, you may want to look into the APM pattern and the BackgroundWorker class.
2) Is the instance's thread automatically terminated when the form closes?
It depends on how the threads were started. A thread can be a background thread or a foreground thread - the latter prevents the application from terminating.
If it's just a couple of lines of code you want to call asynchronously, probably the best way is ThreadPool.QueueUserWorkItem. See: What's the difference between QueueUserWorkItem() and BeginInvoke(), for performing an asynchronous activity with no return types needed
See if you are working with managed Environment, when an object is instantiated it will automatically dispose off if it is out of scope. The Disposal is actually taken care of by Garbage collection.
If you are using UnManaged objects, its your responsibility to close resources before making the object out of scope.
Garbage collection periodically turns on and start collecting all the objects that are out of scope. If you need to work on large objects, you can try using WeakReference class which will hold the object but also expose it for Garbage collection.
Read about WeakReference and garbage collection from here:
http://www.abhisheksur.com/2010/07/garbage-collection-algorithm-with-use.html
I hope this would help you.
I am working through the requirement to make a WPF Application single instance only.
However - I have to pass the command line to the first instance and then perform some UI action.
I am using a Mutext to check for already running instances, I do use NamedPipes to transfer the command line to the already running instance.
But of course I am not in the correct Thread to access "Window1".
I tried to store a reference to "Window1" in a static class and then use the Dispatcher to call a Method in "Window1", however, as soon as I try to access a variable (class wide scope in "Window1") I receive a "Object reference not set to an instance of an object."
The UI Action is to add a new Tab to a TabControl - during initialization of the new Tab some work is done - and the variables are initialized and even the method I want to call works during the init - but when called from the Dispatcher it fails.
Any hints, how to do this? Am I on the wrong track here?
Thanks!
This is easy:
void ProcessCommandLine(string commandLine)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() =>
{
... code to process the command line here ...
});
}
You can call this from your App.Startup and also from your thread that receives messages from the named pipe.
The key considerations here are:
Use of BeginInvoke instead of Invoke to prevent the calling thread from waiting
Use of DispatcherPriority.ApplicationIdle to guarantee the application has finished initializing before the command line is processed
Use of Application.Current.Dispatcher instead of Window1.Dispatcher in case Window1 has not yet been initialzed
That's not right, are you certain that the mutex is passing control correctly to your currently running instance of the application?
If it was a thread UI access issue, you should have received this error: The calling thread cannot access this object because a different thread owns it.
The fact that you're getting an "Object reference not set to an instance of an object." error message means that you've not yet instantiated the object as new.