EDIT 1 :
Apparently, i have started to achieve a 3D rendering in WPF environment in an incorrect way. Ofc there is a solution for my question here below, but i suggest to read the update of Sheridan's answer and use his recommendations to achieve this. It's not only secure, but also better for performance. Although it's a bit complex to understand it, but once you understand it, you can start rendering multiple 3D applications in WPF.
Thanks for your assistance Sheridan !
Question ;
i am quite new in WPF, and i want to design a continuous rendering (like in gaming applications) with WPF. I am using multithreading to provide a better UI control (start/stop button fe). Or the event could be disposed due of using an infinite loop to render the 3D world.
But, my problem is that when running the program, i get an Invalid operation was unhandled error. The issue is that there is an object which is a property of the main thread, thus the new thread might not access it.
from XAML file,
<Grid>
<!-- ui controls omitted ... -->
<Viewport3D Name="myViewport" ClipToBounds="True">
<!-- all inits, camera, pos, ... -->
</Viewport3D>
</Grid>
in main class;
/// <summary>this method is done to render the 3D app in other thread.</summary>
private void Runtime(Viewport3D vp) {
System.Diagnostics.Debug.WriteLine("runtime ");
Render3D r3d = new Render3D(vp);
// actual startup
while (keepRunning) {
r3d.Init3D();
}
}
/// <summary>this method toggles the game runtime</summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void StartOrStop(object sender, RoutedEventArgs e) {
keepRunning = !keepRunning;
if (keepRunning) {
buttonStartStop.Content = "Stop";
// thread
t1 = new Thread( () => Runtime(myViewport) );
t1.Start();
}
else {
buttonStartStop.Content = "Start";
t1.Abort();
}
}
The 3DViewport object is initialized in the XAML file. that's why i am passing it to the new thread, that it can create an object which is using that 3DViewport class.
Here below is a sample of the Render3D class.
// constructor
internal Render3D(Viewport3D v) {
currViewport = v;
}
/// <summary>get called in loops to render gfx</summary>
internal void Init3D() {
// clear rendered view
ClearRenderWindow();
// add landscape
AddLandScape();
}
/// <summary>clear window to re-render gfx</summary>
private void ClearRenderWindow() {
ModelVisual3D mv;
// ***** error got caught here below ******
for (int i = currViewport.Children.Count - 1; i >= 0; i--) {
mv = (ModelVisual3D)currViewport.Children[i];
if (mv.Content is DirectionalLight == false) currViewport.Children.Remove(mv);
}
}
The error is caught at the currViewport.Children.Count method. As previously said, the issue is that the current thread doesn't have ownership of that object. It's the first time in my multithreading experience to face with this issue. I have searched around, but couldn't find a solution.
Does anyone know how to pass the ownership of the Viewport3D-object, or a good workaround ?
Firstly, I would like to say that WPF is not a good framework for developing all but the simplest games... I would advise using a gaming framework like Microsoft's XNA instead.
However, if you insist on using WPF, then I would like to bring the CompositionTarget.Rendering event to your attention. It basically uses the frame rate of the host computer to render regulates graphics passes, avoiding the need to use timers.
You should also take a look at the How to: Render on a Per Frame Interval Using CompositionTarget page at MSDN for more helpful information and code examples.
Also, please read this extract from the book 'WPF Control Development Unleashed: Building Advanced User Experiences':
Some readers may recognize a similarity between this approach and higher-end graphics
subsystems like DirectX. Do not mistake CompositionTarget.Rendering for a good injection
point to create a WPF-based gaming graphics engine. High-end graphics and ultrahigh
frame rates are not the goal of this particular aspect of WPF animation.
Similar to the DispatcherTimer approach, animations based on CompositionTarget.Rendering
are also not time-bound. However, these events are synced with the render thread resulting
in smoother animations than the DispatcherTimer. Also there is no need to start and
stop a timer, although you may have to detach and attach the event handler to improve
performance.
UPDATE >>>
Having discovered that this is just for a course project, I would ignore my previous comment and your code example so far. Don't try to create a new rendering system when there is one already. Instead, you should follow this approach:
Create data objects that implement the INotifyPropertyChanged interface and have X, Y, and DirectionVector (could be a Size struct) public properties.
Add a Move method (or Swim method for your Fish class) in which you update the data objects' X and Y properties dependant on the value of the DirectionVector property.
Add a ListBox control to your UI.
Create a collection property to hold your data objects, add items and bind the collection to the ListBox.ItemsSource property.
Create a DataTemplate to define what your Fish objects look like... you can use the Path class to draw them and even use a RotateTransform to rotate them (the angle can be calculated from the DirectionVector property). In the DataTemplate, you can bind the X and Y properties to the `Margin' property.
Finally, add an infinite loop (possibly with a break out option) and in that loop, iterate through the collection of data objects and call Move() on each one. This will update the data objects' positions in the ListBox.
As a general rule, the only objects that can change thread allegiance in WPF are those that derive from Freezable. (E.g., Model3D is a freezable, and so, therefore, are things like Light and GeometryModel3D.)
Elements that participate directly in the visual tree do not derive from Freezable. They derive from Visual (usually, although not always, via FrameworkElement). Consequently, visual elements are forever associated with the thread on which you created them. Freezables are usually descriptive items that tell visual tree elements what to do. For example, brushes (whether solid, gradient fill, image brush or whatever) are freezables, but to do something with a brush you need to use it as a property of some visual element (i.e. something that's not a freezable) e.g., the Fill of a Rectangle.
So Model3D falls into this category - it is a description of a 3D model, but it doesn't actually know how to render itself. You provide this description to some visual element that does know how to render the model (e.g. Viewport3D).
So it's possible to build up Model3D on a worker thread, and then pass that over to the UI thread.
However, you can only start using a freezable object from some thread other than the one on which it was created after you have frozen it by calling Freeze. This, as the name suggests, prevents further modification. Once a freezable is frozen, it is no longer associated with any particular thread, so you can use it from whatever thread you like.
The intended usage model here is:
Build something complicated on a worker thread
Freeze it
Attach it to something that knows how to render it in the UI thread
This might be appropriate if you wanted to build a complex Model3D that was going to take a long time to construct, and you didn't want to make the application unresponsive while that was happening.
However, this is not of any use if you need the model to be modifiable as time goes on. If that's what you need (and it sounds like it is) then you tend to have no choice but to create the model on the UI thread - if you create a freezable that you never actually freeze (because you need the ability to change it) then you have to create it on the same thread that will render it. When you want to update the model, you either need to ensure updates are done on the UI thread, or you could use data binding, which is able to handle change notification events on any thread, and it will marshal those to the UI thread for you.
However, I'm wondering whether you really need multithreading at all. You give the reason as
to provide a better UI control (start/stop button fe).
That's not really a reason to use a separate thread. There's nothing stopping the UI thread from performing updates to the model and also responding to UI input. You just need to make sure the code that updates the model regularly returns control to the event loop.
The only reason for using a separate thread would be if the calculations that determine what the updates to the model should be are computationally expensive. For example, if you're writing code that performs a complex and highly detailed simulation of some process, and then renders the result, it might make sense to perform the calculations on a worker thread to enable the UI to remain responsive. But even then, once those calculations are complete, you'd need to ensure that the updates you make to the model based on the results of those calculations are done on the UI thread, not the worker thread.
It may be worth considering whether you can get away with building a new model each time round. The user might not actually notice if you drop the old model and instantly replace it with a newly built model. That can enable you to build the entire model on the worker thread, because you can then freeze it. If you build a new model each time, it's safe to freeze, because any time you want to change something, you just build a new model instead of updating the old one.
Yet another variation is to have a model that consists mostly of frozen pieces, contained by some unfrozen top-level elements.
Related
Edit: Ok, after building a minimal example to reproduce the error I have to admit that it's working (Create custom object in Timer.Elapsed, update Collection in ViewModel via Invoke and one way bind readonly GUI dependency property via DataPiping in DataTemplate to ViewModel. All that without freezing the newly created objects).
Nevertheless my real application is not working and I have to find the error somewhere else.
Edit2: Ok, I found the basic problem. My custom object contains a Brush property, which is a DependencyObject and needs to be created on the main thread. I think I can solve that by either freezing only the brush or simply not using the DependencyObject in my custom object. Thanks again guys, learned alot!
Thank you guys for pushing me into creating that minimal example, I really thought this is some kind of design/pattern problem which I don't get. When I found the actual problem in my real application and can't solve it myself i'll come back - with an code example :D
I have a kind of basic question I couldn't find an answer for.
What I basically want to do is:
I have a ViewModel with a ObservableCollection of own objects. This ObservableCollection is bound to an ItemsControl and the Items are displayed based on several DataTemplates. Some of these DataTemplates are using Dmitry Tashkinov's DataPiping approach (Pushing read-only GUI properties back into ViewModel) to push UIElement dependency properties to the ViewModel. All of this works fine.
Now I'm trying to add Objects to the ObservableCollecion while LeftMouseButton is pressed (basically copy/paste the selected object based on mouse position). At first I used the OnMouseMove event but since it seems that there are some delays while adding/displaying the objects and/or refreshing the mouse position it happens that "the mouse is faster than copying objects" and I need to slightly move the mouse around the target position to keep that event firing until all objects between inital and target position are pasted. Basically this works too but has bad user experience.
All approaches to do something while pressing a key i found are based on threading in some way. I tried to use a Timer which is started on LeftMouseDown and stopped on LeftMouseUp. Into the Timer.Elapsed Event I created the new Object and tried to add it to the ObservableCollection.
The Problem is that the Timer.Elapsed Method and ObservableCollection are running on different Threads and I can't add the new object directly. If I'm invoking the collection.add method from the second thread to add the object I'm geting a XAMLParseException saying that DependencySource and DependencyObject needs to be created on same thread. Also freezing the objects is not an option since they are going to be edited later.
Is there a way to copy the object on the main thread before adding it with invoke? Or is there any other common pattern to solve that basic problem?
The Problem is that the Timer.Elapsed Method and ObservableCollection are running on different Threads and I can't add the new object directly. If I'm invoking the collection.add method from the second thread to add the object I'm geting a XAMLParseException saying that DependencySource and DependencyObject needs to be created on same thread
The solution to this would be to either use the dispatcher to marshall the call to the ObservableCollection's Add method to the UI thread:
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
//...
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
//this code gets executed on the UI thread
yourCollection.Add(...);
}));
}
...or use the BindingOperations.EnableCollectionSynchronization method to enable the ObservableCollection to be accessed by multiple threads:
Best/cleanest strategy to update an ObservableCollection from another thread
I know that I cannot spawn different threads and put it in the UI thread to add it in the Visual Tree as it will throw an exception that it cannot access that object because a different thread owns it.
My current scenario is that I am heavily creating UI controls runtime, say like 200 (FrameworkContentElement) controls and add it to the DockWindow. Is it possible for me not to freeze the UI while creating this and try to load them to the UI thread? I cannot even show a progress dialog because that will use the UI thread while showing the dialog while doing work on another thread, that is okay if what I need to handle is data and put it in the UI but this time I need to create these UI controls.
One approach I've thought is create the UI controls and serialize them into MemoryStream and load them to the UI thread, one problem in here is that I have to re-attach the DataContext to the controls but that is fine, at that moment I can delegate it to another thread. Problem still is that is this feasible to do?
I tried mixing Task and Thread object to make the ApartmentState to STA but still no luck.
public static Task<T> StartSTATask<T>(Func<T> func)
{
var tcs = new TaskCompletionSource<T>();
Thread thread = new Thread(() =>
{
try
{
tcs.SetResult(func());
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
EDIT: These controls again are FrameworkContentElement, virtualizing controls in this scenario won't help. This is with FlowDocument controls creating the controls in runtime. Say, Runs, Tables, Paragraphs, etc.. Therefore, ListBox, TreeViews, etc are not applicable in this scenario.
200 controls shouldn't pose that big of a problem to render WPF on a decent machine can take a few thousand primitives.
You can show a progress bar while loading your data and while parsing it. Then you can throttle creating the UI elements if needed by having and off-UI-thread process loop over your data and call UI thread to instantiate controls. You can even separate instantiations by a small sleep to let the screen render, but only use this for VERY heavy UI...
... that being said - if your UI is so heavy you're probably designing it wrong. The question should not be
"how many UI elements can I put before my UI slows down to a drag?"
but
"what's the smallest number of active UI elements that can do the job?".
The word "active" refers to the approach taken by listviews where the actual items are virtualized - they are only created as needed and disposed if not visible. So instead of a DockPanel consider using a virtualizing container, such as a ListView, if your UI allows for it;
I can elaborate further if you can provide an example of your specific UI elements.
i have a winform application in which i have a lot of controls that needs continuos monitoring. For example there is a button and it should be enabled only when two other buttons are disabled, and they disable at separate instances. So what i am doing now is using a thread to monitor the two other buttons in a continuos while loop such as
while(true)
{
if(btn.enabled==false and btn1.enabled==false)
{
bt3.enabled==true
}
}
though it does what i need it seems wrong to me. Also its very expensive considering the number of threads i have to spawn to manage my controls, there are certain controls that needs to check five or six different things to before it can do an action and threading seems the only way possible to me.
Please tell me if there is any other way to do this
Not only is that inefficient, it is incorrect; you should never access a control's properties except from the UI thread, due to thread affinity. Setting properties (the enabled assignment) is especially bad, but reading them (the enabled check) is bad enough.
Rather than continuous monitoring, those forms should update themselves, based on event notifications. For example, by hooking EnabledChanged on the two buttons.
// (in the form initialization code)
btn.EnabledChanged += UpdateButtons;
btn1.EnabledChanged += UpdateButtons;
//...
private void UpdateButtons(object sender, EventArgs args)
{
bt3.Enabled = !btn.Enabled && !btn1.Enabled;
}
you could also (instead) do this at the code that causes the Enabled property to change.
I'm trying to make a listbox that display pictures from internet. The items are provided by binding itemsource to a model that contain the URL of the image and some other properties (title, desc, etc...).
Unfortunately, the list is very slow to load because WPF is trying to download all pictures from the web before showing the list and it makes the application freeze for 15 to 25 sec.
I've read that I should load the picture in an other thread but I don't know where I should do it and how ? Is it better to load all pictures directly in the model (by creating a thread pool only for that - but the problem is that it's not really part of the model/modelview) or is that better to create a background thread that will update directly the list when it has data ?
Thanks !
The easy way is to just just set the Binding.IsAsync property like this:
<Image ImageSource="{Binding propertyThatComputesImageSource, IsAsync=true}" />
Each access to propertyThatComputesImageSource will be done from a ThreadPool thread. If the thread creates the image with ImageCacheOptions.OnLoad, it will block until the image is loaded. So the UI will start up immediately and images will be loaded in the background and appear when they are available.
Binding.IsAsync is a good solution for ten or twenty images, but is probably not a good solution if you have hundreds of images and the load delay is long, since you could end up with hundreds of threads. In that case, load the images outside of databinding entirely by using ThreadPool directly:
ThreadPool.QueueUserWorkItem((state) =>
{
foreach(var model in _models.ToArray())
model.ImageSource = LoadOneImage(model.ImageUrl);
});
This may need to be extended with a Dispatcher.Invoke or two if the model's properties are DependencyProperty, since they can't be accessed from a separate thread.
This technique can be extended to spawn a fixed number of workers to load images and break the work up between them so multiple image downloads are happening, but the number of simultaneous downloads is limited so you don't end up with hundreds of threads.
A very simple approach would be to use a System.ComponentModel.BackgroundWorker (more info) in the view model. Here's a trivial example:
using (BackgroundWorker bg = new BackgroundWorker())
{
bg.DoWork += (sender, args) => FetchImages(viewModelObjectsNeedingImages);
bg.RunWorkerAsync();
}
The BackgroundWorker also makes it very convenient to cancel the background task.
You might also want to look at UI virtualization.
You can use this asynchronous observable collection to be able to bind your data source to your ListBox and still be able to load your data in another thread.
For an example on how to write such a thread, take a look at the BackgroundWorker documentation.
Also, you might want to consider lazy loading of your images, that is, only load the ones that are visible and a couple more at any time. This way, you gain two benefits: don't have to block the UI while fetching the images in your thread, and you can reuse your collection to only hold a few images at a time, preventing filling up the memory with lots of images at once if you plan on displaying, say, a couple of thousand. Take a look here for details on how such virtualization could be implemented.
Thanks to all of you !
All solutions should work :) In my case using IsAsync on the image of the ListBoxItem is good enough (at most there are 50 items). Actually, it's not retrieving the image from a network which was taking too much time !
Unfortunately my problem was somewhere else... It's related to a bug with proxy detection in .NET 3.5 which cause the application to load very slowly :
If there isn't any your_application_name.exe.config file in the application folder with the following code - .NET can take a lot of time to detect the proxy which freeze the application the first time that it accesses to a network :
<configuration>
<system.net>
<defaultProxy enabled="false"/>
</system.net>
</configuration>
Now unfortunately due to the fact that WinCE Usb Device Arrival / Removal exposes itself via WindowsMessages I have to ensure that a certain (non-UI) component is not created on a background thread. I would like to assert this via an exception but am lacking the code for the assertion.
This component creates a MessageWindow* and uses it to receive usb arrived/removed messages. The issue is if someone creates this component on a background thread (not necessarily; IsBackground = true) when the thread exits the window will be destroyed.
Any ideas?
*as an aside I still don't know why Form doesn't inherit from this class
Update
I think my version 1 wasn't very clear. So this is v2.
When you create a MessageWindow or a Form for that matter on a thread, when that thread exits the Window/Form is destroyed.
My component is creating a "hidden" message window to intercept some important events, ergo I do not wish for it to be destroyed. Therefore I must somehow ensure that the code that creates the form is running on the "Main UI" thread.
If possible i'd like to avoid passing down a reference to the "main" form to this component as it is (architecturally speaking) supposed to be miles away from the UI.
Update
Moving logging question to a separate Q.
Ok, I understand that you don't want for your component to "know" about the main window -- makes sense.
How about this: How about if you make sure that you always instance your component on the main thread? You component will create it's listener window on the constructor's thread.
If you do that, then you just need to make sure that you call the constructor from the main thread. I'm making some assumptions about your code, but I'm guessing that you must have some class in your architecture that knows about both the UI and your component. Create your component there, using a callback, and the main form's InvokeRequired/Invoke methods.
In forms, you use the InvokeRequired property.
Why not create the non-UI component on a background thread and when you go to update any UI component just look to see if invokeRequired then get back on the main thread to actually do the update.
You should have nothing really tying up the main event thread, IMO.
You can use it in this way:
void MyCallback()
{
if (form1.InvokeRequired) { // form1 is any existing gui control
form1.Invoke(new Action<>(MyCallBack));
return;
}
// your logic here
}
Hey there: I had an idea about your problem. This is just a random thought, and I don't know for sure whether it will work (I have not tested, nor even compiled this -- it just hit me):
What if you get the window handle of the main window of your app, then build a Control around it (I'm assuming that you have a gdi-based app, like Winforms)?
this code might not compile, but it's close (it would go into your component -- note that it would make your component require a gdi windows/winform app, as opposed to a console or WPF app).
If you do try it, I'd love to hear whether it worked for you.
using System.Diagnostics;
using System.Windows.Forms;
void Init()
{
// get handle to the main window
intPtr mainWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
Control mainWindow = Control.FromHandle(mainWindowHandle);
if(mainWindow.InvokeRequired)
mainWindow.Invoke(SetupMessageWindow);
else
SetupMessageWindow();
}
void SetupMessageWindow()
{
// do your thing...
}