Access to styles from several UI Threads - wpf

Our team developing rich WPF application.
Recently we added logic to show some view as independent non-modal window. User have ability to open as many such windows as he wants. It works good, but if any window will show modal confirmation - then all windows will be blocked.
We found solution - open non-modal windows in separate thread. And now we have issue with shared resources - "InvalidOperationException: The calling thread cannot access this object because a different thread owns it."
It's related with reference to Style in xaml during creation of view in separate thread.
Styles exists in separate project.
What solution could be here?
Code, which shows window in separate thread:
Thread newWindowThread = new Thread(() =>
{
new Window().Show(); // simplified, here are creation of
// window, setting datacontext, rest of properties
System.Windows.Threading.Dispatcher.Run();
});
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.Start();
How to make resources available for all UI threads (under UI thread I mean each separate thread, which creates and shows non modal Window)?
Maybe there are exist another more high level solution?

Related

Removing ViewModels in Prism when Closing Window

I have a winform application with data grid rows with some icons.
When the user clicks on one of the icons, a WPF window opens.
I have created this WPF window using Prism i.e. it has shell and regions mapped to view.
The issues I am facing is:
When I tried to close the WPF window, I get the exception "Cannot set Visibility or call Show, ShowDialog, or WindowInteropHelper.EnsureHandle after a Window has closed."
I understand that we can resolve the issue by hiding the window instead of closing it.
However, this makes my ViewModel and Services representing the older WPF window.
I have kept the static counter in the ViewModels and observed that every time, I open the WPF window, static count increases which means my old view models are not getting destroyed.
I would like how to handle this scenario correctly so that when I close the window everything related to the window should be disposed off.
I tried to do container.dispose in ShellViewModel, however, still it did not work.
There are two aspects here. Firstly, you can use either RegionMemberLifetimeAttribute on your view model or implement IRegionMemberLifetime to make Prism create a new instance each time.
Secondly, you have to create your own RegionBehavior (or take it from this Github Issue) to make Prism dispose view models.

MultiThread in WPF

I have several projects, each of thern have UserControl to manage them. All projects are in one solution and working simultaneously. all UserControls are in TabControl. But if one project don't handle his exception, all solution fail down. How can i run each UserControl in another Thread ?
I have several classes, they are models in MVVM. All of them have ViewModel and View. Now all classes start and workig in one thread. If one of then throw exception< all app will fail down. I want taht all models working in individual thread. But all Views of taht models are together in TabControl. How i can organize this sheme?
You can't. WPF has one, and only one, user interface thread. Modifying user interface elements from a background thread won't work and will raise an exception. (EDIT: This is not entirely correct, apparently it is possible to start individual windows in their own threads.)
If you have a problem with uncaught exceptions, have a look at the Application.DispatcherUnhandledException event, which allows you to register a central exception handler for your complete WPF application. If you set e.Handled = true;
at the end of your DispatcherUnhandledException handler, exceptions will cause your application to fall back to the user interface rather than terminating the application.
More information:
WPF global exception handler

Cross thread violation while adding UserControl from worker thread to Main UI thread in Winform

I have an application which tab page based. To decrease the startup time I am creating only the tab page which is shown to the user.
After launching the Form, I used BackgroundWorker to create other tab pages. Tab pages contains usercontrols with databinding.
It is working fine. The issue is: With one tab page I am getting cross thread violation. That tab page having databinding also.
So what will be problem in this scenario?
Thanks is advance.
WinForms controls have thread affinity. The means they should be accessed on the same thead they are created on. This is because WinForms is actually just a wrapper around Win32 functionality and the code that manages your windows and child controls in Win32 is not thread safe. Hence your Form and child controls should only be accessed on the same thread they are created.
In your case you should not be creating TabPage instances using a BackgroundWorker thread or indeed any other thread than the main thread which is the location I assume you have the main Form that contains the TabControl you are adding the pages into.
Often developers get lucky and manage to use controls in different threads to which they were created and it does not crash. But this is just pure luck and sooner or later it will start failing.

regarding wpf dispatcher

I am new to WPF and have a question regarding dispatcher and Delegate.Invoke.
In a windows forms application, we can use the invoke method to make changes to UI controls from other threads. This works because invoke “executes the specified delegate on the thread that owns the control's underlying window handle” (as per msdn).
My question is:
Why doesn't Invoke work on WPF? It should be allowed to make changes to UI as the thread that owns the UI control gets to execute the delegate, but still it throws a runtime exception that “a thread is trying to modify an object that is owned by a different thread”.
How does the dispatcher manage to make changes to WPF controls while Invoke fails?
Is it possible to do cross thread programming in WPF without using dispatcher or background worker?
1) why doesn’t invoke work on wpf?
It works fine, but perhaps you're not using it correctly. I suggest you read the documentation
It should be allowed to make changes to UI as the thread that owns the UI control gets to execute the delegate, but still it throws a runtime exception that “a thread is trying to modify an object that is owned by a different thread”
Perhaps you created a UI object on a worker thread, then tried to add it to the main UI on the UI thread ? Without seeing your code, it's only a guess...
2)How does despatcher manage to make changes to wpf controls while invoke fails?
This question is not very clear, but it's probably related to the first question anyway...
3) Is it possible to do cross thread programming in wpf without using despatcher or background worker?
If you need to manipulate the UI from a worker thread, you have to use the dispatcher. BackgroundWorker also uses the dispatcher (indirectly, through the ISynchronizationContext interface) to raise events on the UI thread. There's no way around it.

WPF : Is it impossible to UI load in background thread?

I've making a some application which build a huge-sized FlowDocument. The elapsed time of building FlowDocument was about 3~4 seconds.
So I like to building FlowDocument in BackgroundWorker, not UI thread. but BackgroundWorker can't return WPF UI object. (It occured InvalidOperationException exception.)
how can i solve this problem?
If you want to build a FlowDocument in another thread, it has to be a second UI-type thread, not a BackgroundWorker. In spite of what the documentation says, you CAN build more than one UI-type thread. However, you cannot create UI objects in one thread, and use them in another. You could save your FlowDocument to disk and then reload it in the foreground UI thread, though.
This article has a good example with two UI threads, and in fact I have used this code to process XPS files in a background thread, very similar to what you are doing. Make sure your second UI thread is set to STA apartment state, and as I said, do not try to use any UI objects created in one thread, in a different thread. It won't work.

Resources