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

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.

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

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?

Access UI element from non UI thread

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.

C# - How to change value of a progress bar in a secondary thread

In my program I import millions of records to a SQL Server database with the help of SqlBulkCopy class. Since this is a heavy lifting it takes quite some time. While the process goes on I want to show the progress in a progressbar control. To be notified for the rows copied I've done this:
.......
bulkCopy.NotifyAfter = 2000;
bulkCopy.SqlRowsCopied += new SqlRowsCopiedEventHandler(bulkCopy_SqlRowsCopied);
.......
Now in the bulkCopy_SqlRowsCopied method I want to change the value of the progress bar. But I think I need to make it on a seperate thread. How can I do this?
You can have one extension class, like
public static class ControlExtensions
{
public static void Invoke(this Control control, Action action)
{
if (control.InvokeRequired) control.Invoke(new MethodInvoker(action), null);
else action.Invoke();
}
}
Now when ever and where ever you want to update status of progress bar, you can do
progressBar.Invoke(() => { progressBar.PerformStep(); };
Hope this works for you.
You could execute your copy in a BackgroundWorker and use ReportProgress to update your progressbar...
You can find an example at http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx.
The use of a BackgroundWorker for time-consuming operations is good because your UI (with the main thread) is free to be updated/refreshed, making user experience better.
For non-collection properties WPF will marshall the value on to the UI thread for you. So if you have a ViewModel with a progress property that raises the PropertyChanged event you can bind your ProgressBar to the ProgressBar.
For this to work, your ViewModel instance should not be a DependencyObject (but that is a bad idea for so many reasons). This way you can reference it from your background thread and set the Progress property.
Using the Invoke() Method of the ProgressBar Control in your EventHandler "bulkCopy_SqlRowsCopied", make sure you set the NotifyAfter property of the SqlBulkCopy class to an amount that would reflect some form of percentage.
Now in the bulkCopy_SqlRowsCopied method I want to change the value of the progress bar. But I think I need to make it on a seperate thread. How can I do this?
If you are using .Net 4.0 you could start your bulk copy in a Task, other versions you could use the ThreadPool, create your own thread
Task.Factory.StartNew(MyBulkCopyMethod);

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