Access UI element from non UI thread - c#

I've got small WPF / MVVM example project with two visual elements (a ComboBox and a simple TextBlock). Both elements are bound to a property of my ViewModel:
Properties MainViewModel.cs
public const string WelcomeTitlePropertyName = "WelcomeTitle";
private string _welcomeTitle = string.Empty;
public string WelcomeTitle
{
get{ return _welcomeTitle;}
set
{
_welcomeTitle = value;
RaisePropertyChanged(WelcomeTitlePropertyName);
}
}
public const string PositionsPropertyName = "Positions";
private ObservableCollection<int> _positions = new ObservableCollection<int>();
public ObservableCollection<int> Positions
{
get{ return _positions; }
set
{
_positions = value;
RaisePropertyChanged(PositionsPropertyName);
}
}
Bindings MainWindow.xaml
<StackPanel>
<TextBlock Text="{Binding WelcomeTitle}"/>
<ComboBox ItemsSource="{Binding Positions}" />
</StackPanel>
Now I change both properties from a non UI thread like this (which is not allowed, as far as I know it):
System.Threading.ThreadPool.QueueUserWorkItem(delegate
{
int i = 0;
while(true)
{
Positions.Add(i); // Solution 1: this throws NotSupportedException
WelcomeTitle = i.ToString(); // Solution 2: this works
i++;
}
}, null);
Question:
Why does solution 1 throw a NotSupportedExpection (not allowed to change collection from non dispatcher thread) while solution 2 works as desired?

Now I change both properties from a non UI thread like this (which is
not allowed, as far as I know it)
In general, changing property values is perfectly fine no matter what thread you are on. Problems and restrictions may come up when changing a property has an "interesting" side effect.
In this case both of the properties being changed produce interesting side effects, and the difference in observed behavior is due to these side effects being handled (from framework code, which you do not get to see directly) in different ways.
Why does solution 1 throw a NotSupportedExpection (not allowed to
change collection from non dispatcher thread) while solution 2 works
as desired?
When a binding source's properties are changed the WPF binding system responds by making the corresponding updates to the UI; however, when the changes are made from a background thread then the binding system's event handler will also run in the background thread and will not be able to update the UI directly. This is true for both the cases in question here.
The difference is that for "simple" property value changes the binding system automatically detects that it's not responding to the change on the UI thread and dispatches the UI changes to the correct thread using Dispatcher.Invoke, but when the observable collection is modified this dispatch does not happen automatically. The result is that the code that updates the UI runs on the background thread and an exception is thrown.
The solution
There are two things either one of which can solve this problem:
Make the property change in the UI thread directly
If the change is made on the UI thread then any PropertyChanged handlers will also run on the UI thread, so they will be free to make any UI changes they want. This solution can be enforced in your own code and will never result in a problem, but if no UI changes are required the extra work of dispatching to the UI thread will have been done for no benefit.
Make sure the PropertyChanged handler dispatches any UI-related changes to the UI thread
This solution has the benefit that it only dispatches work on demand, but also the drawback that the event handler (which might not be your own code) must be explicitly programmed to make the dispatch. .NET already does this for plain properties, but not for ObservableCollection. See How do I update an ObservableCollection via a worker thread? for more information.

The simple Property binding is automatically dispatched to the GUI thread by WPF and can be changed from a non-UI thread. However, this is NOT true for collection changes (ObservableCollection<> BindingList<>). Those changes must happen the UI thread the control was created on.
If I remember correctly, this was not true (solution 2 did not work also) in the early years of WPF and .NET.

Related

How to create main thread object and add to collection from other thread?

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

Is it safe to bind WPF controls to data updated in Timer?

I have a WPF application that is updating its data model within a timer which updates its data at 1 Hz. As I understand it, a Timer works on a separate thread from the GUI. Everything seems to work great, but I'm reading around and see conflicting reports on whether it's ok to update data on a thread different from the GUI thread. We are running with .NET framework 4 Client Profile. The below article says things are fixed in 4.5 but it still isn't clear to me that it is. Can someone clarify this for me? We aren't using collections in our binding as of yet. Is that why we're not having trouble.
WPF Databinding thread safety?
yeah. It is thread safe. INotifyPropertyChanged is always marshalized to UI thread from other threads.
There is no need to dispatch PropertyChanged from another thread to UI thread, as the PropertyChanged event is automatically marshalled to the UI dispatcher.
As a MSDN article says:
Note that in WPF, things are different and the code shown in Figure 5
works even if the Status property is data-bound to a TextBlock. This
is because WPF automatically dispatches the PropertyChanged event to
the main thread, unlike all the other XAML frameworks. In all other
frameworks, a dispatching solution is needed.
However, it is only true for change notifications on scalar properties (i.e. PropertyChanged event). Collection change notifications (INotifyCollectionChanged.CollectionChanged event) don't work that way, they must be raised on the UI thread manually. That is, when using INotifyCollectionChanged (such as with an ObservableCollection), these changes are not marshaled to the UI thread. This means that if you modify collection from non UI thread, you’ll take an exception. For example, there is some ViewModel We’re in the ViewModel class and we don’t use the Dispatcher to update UI. So I advise to you to use David Rickard's approach:
public static class DispatchService
{
public static void Invoke(Action action)
{
Dispatcher dispatchObject = Application.Current.Dispatcher;
if (dispatchObject == null || dispatchObject.CheckAccess())
{
action();
}
else
{
dispatchObject.Invoke(action);
}
}
}
and:
DispatchService.Invoke(() =>
{
this.MyCollection.Add("new value");
});
David Rickard article at msdn blog.
Update:
yeah, the article uses MVVMLight framework. However, it is not correct that MVVM Light uses Dispatcher to marshal scalar property to UI thread. It can be seen from source code of ViewModelBase class from MVVM Light that there is no marshal between threads to update scalar property. Please, see RaisePropertuChanged() method.
In order to dispel any doubts on dispatching scalar properties I've made a test:
XAML:
<TextBlock Text="{Binding Number}" FontSize="188" Foreground="Red" />
ViewModel:
public int Number { get; set; }
private void UpdateNumber()
{
Task.Run(() =>
{
System.Timers.Timer timer = new System.Timers.Timer(250);
timer.Elapsed += (sender, eventArgs) =>
{
Number++;
OnPropertyChanged("Number");//No exceptions, no errors
};
timer.Enabled = true;
});
}
Update 1:
There is no doubt that INotifyProperyChanged event is automatically dispatched by WPF to UI Thread. I believe a MSDN article and the link you've shown in your question:).
Pay attention to this: This is because WPF automatically dispatches the PropertyChanged event to the main thread, unlike all the other XAML frameworks.
No, it is not thread safe. A common way to fix that is by switching to the UI thread in the raiser of the notify property changed event.
Updating the view or viewmodel 1000 times per second is, in general, useless because the display is only updated 60 times per second or so and the average user is not able to read a thousand values per second in text.
The same code that raises the notification event could throttle the number of times the event gets raised per second.

Cannot get Begin.Invoke, ObservableCollection and background thread to work

This might be an easy/stupid question, but I cannot simply get the three things in the title to work. I am following the advice from the following SO answer:
WPF listbox dynamically populated - how to get it to refresh?
Create an ObservableCollection and set your ListBox.ItemsSource to that collection. Because the collection is observable, the ListBox will update as its contents change.
However, if your real operation is blocking the UI thread, this may
prevent WPF from updating the UI until the operation completes
(because the WPF data binding infrastructure doesn't get a chance to
run). So you may need to run your lengthy operation on a background
thread. In this case, you will not be able to update the
ObservableCollection from the background thread due to WPF
cross-threading restrictions (you can update properties, but not
collections). To get around this, use Dispatcher.BeginInvoke() to
update the collection on the UI thread while continuing your operation
on the background thread.
I created ObservableCollection and attached it to the ItemSource of my ListBox:
private ObservableCollection<Employee> employeeList;
searchList.ItemsSource = employeeList;
I create a thread and instruct it to run the function that populates the ObservableCollection (I am passing text string and ObservableCollection):
Thread thread = new Thread(() => ldapConnector.Search(textbox.Text, employeeList));
thread.Start();
ldapConnector is a separate class that I initialized, when I started the program. And then I get the following error (pointing at thread creation line):
The calling thread cannot access this object because a different
thread owns it.
As I understood from that post, I would need to run Begin.Invoke() method right after thread creation like this:
Dispatcher.BeginInvoke(new Action(()=>{
searchList.ItemsSource = employeeList;
}));
What I am doing wrong and how to fix it?

passing object ownership to other thread in WPF application

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.

Equivalent of PostMessage in C# to synchronize with the main thread with MVVM?

I must be retarded with searching, because here's another seemingly common problem that I haven't been able to solve.
Here's my problem -- I am using WPF and MVVM, and I have a statemachine that executes in the model. If an error occurs, I need to pass information up to the ViewModel to display the error. This part seems to work okay. When the user clicks the desired behavior, the code in the model continues, and looks at the object the user interacts with to determine what to do next.
The problem is that the model needs to reload a file, which updates the GUI with the contents of said file. Because the model is executing in a thread, you can imagine what I'm going to ask next -- how the hell do you synchronize with the GUI properly? In MFC, I would have used either SendMessage or PostMessage to accomplish the GUI update.
I've read articles for WinForms that suggest using InvokeRequired to automatically call BeginInvoke if necessary. I actually didn't know that BeginInvoke would accomplish what I wanted, so I was encouraged to learn this.
How do I actually call BeginInvoke from my model? Does this method even apply to WPF? I went ahead and implemented a delegate and then called Invoke, but I get the same error that tells me the collection can't be modified from this thread. I also tried BeginInvoke for the hell of it, but I assume that also wouldn't work because it would just launch from a different thread anyway.
Confused. If I have missed something really obvious that's been posted about all over the internet, go ahead and give me a verbal lashing, I probably deserve it.
EDIT - I should probably also add that I am looking for something other than a timer or BackgroundWorker-based solution, unless that's the only way to solve this in WPF / MVVM. Also, I wonder if any of the MVVM toolkits would have facilities for this sort of thing already...
If you want to schedule some work from a background thread to the UI thread in WPF, use the DispatcherObject. Here's a nice article on how to Build More Responsive Apps with the Dispatcher.
Update: Note that if you use an event to send notifications from the Model to the ViewModel, you still need to switch to the UI thread somewhere. Whether that switch should be in the Model or the ViewModel is a good design discussion, but it's orthogonal to your question.
The event will be raised on the corresponding Dispatcher thread. Since you need to get to the UI thread, you need to use a Dispatcher that is created on the UI thread. The easiest way to get one is to use the DispatcherObject.Dispatcher property on one of the UI elements. The alternative is to create one in your Model or ViewModel. If you are a design purist, I would suggest you create the Dispatcher in your Model and dispatch the call back to the UI thread before you raise the event to which the ViewModel is listening. This way all the thread switching and management is contained in your Model and the ViewModel works as a single-threaded on the UI thread only.
I think that your ViewModel really shouldn't know anything about the View, including whether or not it's a WPF UI, or whether or not that UI even has the concept of a Dispatcher thread, so the red flag should fly as soon as you start writing code in your ViewModel that attempts to CheckAccess() or InvokeRequired in order to marshal some code to the UI thread. Instead I'd have the model raise an event that the View can listen for and update itself accordingly, or have the ViewModel expose a property (eg. bool FileIsLoading) that the View simply binds to in order to detect and display what the model is doing asynchronously, and it's the ViewModel's responsibility to ensure that the value of that property is accurate.
For example:
public partial class MainWindow : Window {
private ViewModel _model = new ViewModel();
public MainWindow() {
InitializeComponent();
DataContext = _model;
}
private void Button_Click(object sender, RoutedEventArgs e) {
_model.Run();
}
}
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Click="Button_Click"
Content="Run"
IsEnabled="{Binding IsIdle}" />
</Grid>
</Window>
public class ViewModel : INotifyPropertyChanged {
private bool _isIdle = true;
public bool IsIdle {
get { return _isIdle; }
set {
_isIdle = value;
OnPropertyChanged("IsIdle");
}
}
public void Run() {
ThreadPool.QueueUserWorkItem((state) => {
IsIdle = false;
Thread.Sleep(10000);
IsIdle = true;
});
}
#region INotifyPropertyChanged Implementation
protected void OnPropertyChanged(string propertyName) {
PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if (propertyChanged != null) {
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
I've got another approach that seems to work, and I just wanted to throw it out there to get some comments (if anyone is even reading this question anymore!).
I started to use the MVVM Light Toolkit's Messenger class, and it seems to work really well for me. For example, let's take the ProgressBar as an example. I registered two messages with my ViewModel for setting the progress value and progress maximum. Then in my model, as it sets up the tasks and overall process, it sends these messages. When the VM receives the messages, it just updates databound values, and my GUI updates automatically! It's super duper easy, but I was wondering what you all thought about this approach. Is anyone else doing this without incident?

Categories