I'm able to run 2 or more WPF windows on different thread.
The problem is that now my application in splitted in many windows.
What I really want is have a main window containg a grid in which every cell contains an element managed by a different thread.
Is it possible to create a UIElement/Component managed by a thread that is not the one which manage the parent/ containing window?
or
Is it possible to encapsulate a window that runs on a different thread in some frame/UIElement?
Thanks
Is it possible to use a MediaElement to project a window into a Panel?
"What I really want is have a main window containg a grid in which every cell contains an element managed by a different thread."
One way to go about this would be to create your elements normally in the cell. Create a regular class ViewModel that doesn't touch the UI but runs on it's own thread. This class is the brains behind what you're actually trying to DO with in your cells, not what you're trying to SHOW in your cells. This ViewModel class should implement INotifyPropertyChanged when it's data is has been updated. In your MainWindow.cs file you can set your cell elements' DataContext to these ViewModels. Lastly, in your XAML you can Bind things you're trying to show with the Properties in your ViewModel.
I know I breezed over a lot of details, but it's a starting point. Lots of help to be had around here if you need any.
It's not possible in WPF and even if it was it would have been a bad idea:
It's not possible in WPF because WPF element can only be used by the thread that created them, if you add a child element from another thread they wouldn't be able to communicate.
In pure Win32 it is possible - but it joins the two threads message queues so the threads are no longer independent (so even if you find a hack that makes it work with WPF it still doesn't help you)
Any thread that has UI and performs a long running task can hung the entire system - so it's impotent to never perform any long running task in a UI thread - instead run the long task in a background thread
because you have to keep the UI thread responsive -> it should never be busy for a noticeable length of time -> it can handle all your windows because it's not too busy.
Related
I have a WPF executable and I want another program to launch it and set this launching program as the parent windows of my WPF executable (The main purpose is that when the launching program is closed the WPF executable is also shut down). I thought I could make it like this: I pass the Hwnd as one command line parameter (as integer-string), and I can call the SetParent or whatever function inside my WPF executable code to specify the parent. However, I can't make it work. Can anybody tell me how to do that, or any other way to do that? Thanks!
You can't. Window handles are per-process.
Besides, you wouldn't want to. It's problematic enough to have a parent window in another thread -- that causes the message queues of the two threads to become attached, i.e., they effetively share the same message queue from then on. So now if either thread locks up, or does some lengthy processing, both threads are frozen. (And there's no way to later detach the message queues, as far as I'm aware.) Imagine trying to extend this cross-process.
If you must start some new code and use an existing window as a parent, you can't go cross-process. You would have to load the WPF code into your process and call a method in it, passing your parent window as a parameter. The simplest way to load that code into your process would be to change your WPF application to a class library (.dll), and either add a reference to that .dll, or load it dynamically using Reflection.
As #Joe White said you cannot achieve this straightaway ... I think I can "guess" what you are getting at ....
You probably have a WinForm MDI parent (its exe already) and you want to launch another WPF window (another exe) as its child. Am I correct?
Hmmmm then you would have to create a new WinForm child window with WinFormWPFHostApp in it and then refer the WPF assemblies to this project and try to host the Content of the MainWindow from that other WPF application.
refer this article...
I want to create a control which takes a while to create (Pivot) and then add it to the visual tree. To do this i would need to change the dispatcher of the control (and its heirachy) before adding it to the VisualTree.
Is this possible? Are there any implications of walking the controls trees and setting the _dispatcher field via reflection?
AFAIK this only works with Freezable derived classes. The best solution I see is to create the control on the UI Thread and show a progress bar during creation. To make this possible you will have to create the control in portions an let the progress bar update itself once in a while. This not only necessary for the progressbar but also will make sure that you application does not block.
Pseudocode (execure in extra thread):
this.Dispatcher.BeginInvoke(UpdateProgress(0));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(0,25));
this.Dispatcher.BeginInvoke(UpdateProgress(25));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(25,50));
this.Dispatcher.BeginInvoke(UpdateProgress(50));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(50,75));
this.Dispatcher.BeginInvoke(UpdateProgress(75));
this.Dispatcher.BeginInvoke(bigControlBuilder.Build(75,100));
this.Dispatcher.BeginInvoke(UpdateProgress(100));
this.Dispatcher.BeginInvoke(this.Children.Add(bigControlBuilder.GetControl()));
Update:
To make complex control more responsive you could also try UI-Virtualization/Data-Virtualisation:
Only load and show those visual items of the data items that are currently visible to ther user. Do not load and show visual items that are scrolled offscreen are to small to see or are in any other way invisible to the user. Upon userinteraction unload items that become invisble, load items that become visible.
To answer your question, I suppose it is possible to set _dispatcher using reflection but I would not recommend it at all. There is a deeply ingrained notion in WPF of thread affinity and STA so I wouldn't mess with that.
bitbonk's approach is a good one.
Another approach we have used in a project of ours was to create a second UI thread and have a progress indicator be rendered by the second UI thread while the first UI thread is building the UI. As long as the progress bar stays in the visual tree owned by the second UI thread, you should be good.
Im working on a reporting system, a series of DocumentPage are to be created through a DocumentPaginator. These documents include a number of WPF components that are to be instantiated so the paginator includes the correct things when later sent to the XpsDocumentWriter (which in turn is sent to the actual printer).
My problem now is that the DocumentPage instances take quite a while to create (enough for Windows to mark the application as frozen) so I tried to create them in a background thread, which is problematic since WPF expects the attributes on them to be set from the GUI thread. I would also like to have a progress bar showing up, indicating how many pages have been created so far. Thus, it looks like Im trying to get two things to happen in parallell on the GUI.
The problem is hard to explain and Im really not sure how to tackle it. In short:
Create a series of DocumentPage's.
These include WPF components
These are to be created on a background thread, or use some other trick so the application isnt frozen.
After each page is created, a WPF ProgressBar should be updated.
If there is no decent way to do this, alternate solutions and approaches are more than welcome.
You should be able to run the paginator in a background thread as long as the thread is STA.
After you've set up your thread, try this prior to running it.
thread.SetApartmentState(ApartmentState.STA);
If you really must be on the GUI thread, then check out the Freezable class, as you might have to move the objects from your background thread to the GUI thread.
If the portions that require the UI thread are relatively small, you can use the Dispatcher to perform those operations without blocking the UI. There's overhead associated with this, but it may allow the bulk of the calculations to occur in the background and will interleave the work on the UI thread with other UI tasks. You can update the progress bar with the Dispatcher as well.
My guess is that everything that is time-consuming to create is within your Visual. If so, there is an easy solution: Don't create actual DocumentPage objects and their associated Visuals until DocumentPaginator.GetPage() is called.
As long as the code that consumes your document only requests one or two pages at a time there will be no performance bottleneck.
If you're printing to the printer or to a file, everything can be done on a background thread, but if you're displaying onscreen you only need to display a few DocumentPages at a time anyway. In either case you won't get any UI lockups.
The worst case scenario would be an app that displays pages in a thumbnail view. In this case, I would:
The thumbnail view would bind its ItemsSource to a "RealizedPages" collection which initially is filled with dummy pages
Whenever a dummy page is measured, it queues a dispatcher operation at DispatcherPriority.Background to call DocumentPaginator.GetPage() and then replace the dummy page in the RealizedPages collection with the real page.
If there are performance concerns even with realizing a single page because of the number of separate items, this same general approach can be used within whatever ItemsControl on the page has the large number of items.
One more note: The XPS printing system doesn't ever process more than one DocumentPage at a time, so if you know that's your client you can actually just keep returning the same DocumentPage over and over again with appropriate modifications.
Elaborating further on Ray Burns' answer: Couldn't you have your dataprocessing done in a class on a background thread and then databind the DocumentPage's properties to this class when the processing is done?
A little late to the game on this one, but I just worked out a solution to this so I thought I would share. In order to display the UI elements they have to be created on the UI thread on which they will be displayed. Since the long running task is on the UI thread, it will prevent a progress bar from updating. To get around this, I created the progress bar on a new UI thread and created the pages on the main UI thread.
Thread t = new Thread(() =>
{
ProgressDialog pd = new ProgressDialog(context);
pd.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
pd.Show();
System.Windows.Threading.Dispatcher.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
Action(); //we need to execute the action on the main thread so that UI elements created by the action can later be displayed in the main UI
'ProgressDialog' was my own WPF window for displaying progress information.
'context' holds the progress data for my progress dialog. It includes a cancelled property so that I can abort the action running on the main thread. It also includes a complete property so the progress dialog can close when the Action has finished.
'Action' is the method used to create all the UI elements. It monitors the context for the cancel flag and stops generating the UI elements if the flag is set. It sets the complete flag when it is done.
I don't remember the exact reason I had to set Thread 't' to an STA thread and IsBackground to true, but I am pretty sure it won't work without them.
I'm trying to write a background worker that processes a flowdocument. I can't access the properties of flowdocument objects because of the thread verification. I tried to serialize the document and loaded it on the worker thread which actually solved the thread verfication issue. However, once the processing is complete I also need to use things like TextPointer objects. Those objects now point to a objects in the copy not the original.
Can anyone suggest the best way to approach such background processing in WPF?
You can't, WPF objects can only be accessed from the thread that created them so by definition you can't do any background processing on them.
But, as you already discovered you can use serialization techniques to create a copy in another thread and you can serialize the result back.
XamlWriter/XamlReader can serialize almost every WPF object but can be slow on large object graphs.
And for TextPointer maybe you can use GetOffsetToPosition/GetPositionAtOffset to recreate an equivalent TextPointer back in the main thread.
Another options is to use freezables, objects that inherit from Freezeable can be used from other threads (after the Freeze method is called), documents are not freezable but drawing and geometries are - so you may be able to transfer document "fragments" between threads as drawings.
...or...
"What evil in the depths of WPF have I awoken?"
I'm creating a Canvas on a background thread and rendering it to a bitmap. I've had this working in production code for over a year now without problems. I do the following:
create a Canvas object
create a new NameScope object
assign that NameScope to the Canvas
draw whatever I want on the Canvas
call canvas.Measure() with the Canvas's size
call canvas.Arrage() with the Canvas's available rect
call canvas.UpdateLayout()
render the Canvas
In the draw step, I have always just called canvas.Children.Add() to put UIElements onto the Canvas. This has always worked.
Now, for some inexplicable reason, in one specific case in the application I'm working on, the call to canvas.Children.Add() hangs indefinetely, blocking my background thread. I can't think of anything I'm doing differently between the code that has been working for over a year, and this one specific case.
Can anyone suggest possible reasons why a call to canvas.Children.Add() would hang like this?
Edit: The background thread is an STA thread (the background thread processing model was put in place because I couldn't process images using WPF on a MTA thread), so the thread apartment model shouldn't be the culprit.
Edit #2: While I understand why people are suggesting I try Dispatcher.BeginInvoke() from my background thread, I don't like that option for two reasons:
I want my background thread processing to be synchronous on that thread. My background thread has a queue that other threads submit image jobs to, and my background thread processes each job as it gets to them. Using Dispatcher.BeginInvoke() adds another layer of complexity that I'd rather avoid.
I've never needed to until now. Doing this background processing synchronously on my background thread has just plain worked. I'm trying to determine what could possibly be different about this bizarre edge case that causes this code to not work. If I can't get it to work, I'll end up rewriting this processing code without WPF, which I'd also rather avoid.
What apartment model are you using for your background thread?
I believe WPF needs to run on the STA thread. When you spawn the background thread, try settings it's apartment to STA.
Update:
If the STA thread is not the problem, then I would try breaking your canvas drawing up into chunks. Basically if you do a:
Dispatcher.BeginInvoke(...)
from your thread, the provided delegate gets pushed onto the back of the dispatcher queue, allowing other queued tasks to execute.
Update 2:
You could also try debugging into the source code for the Canvas object using the .NET framework reference sources. You can enable this by turning on "enable .net framework source stepping" in the debugging options under Tools->Options.
Try calling Dispatcher.Run() in the background thread.