When binding to a property in Silverlight 3 and 4, the Windows Phone 7 version silverlight and in WPF 3.5 and 4 will property change notifications always be marshalled to the UI thread? Are you aware of any scenario where I can not rely on that and would have to do the marshalling in my code?
I did some experiments...
INotifyPropertyChanged
If you make a change to a property from a background thread, and it fires INotifyPropertyChanged from that background thread, and the property is databound, then...
WPF: it works (i.e. the databinder marshals it to the UI thread)
Silverlight5 and WinRT: it fails (i.e. the databinder doesn't marshal)
Phone: I assume it's the same as Silverlight, but haven't tried.
DependencyProperty
What if the property is a dependency property rather than INotifyPropertyChanged? What if you alter this property from a background thread? Well, I haven't done any experiments, but I read that it doesn't do any marshalling.
INotifyCollectionChanged (e.g. ObservableCollection)
If you add/remove elements in an ObservableCollection from a background thread, and the collection is databound to a listbox or similar, then what happens?
WPF: As of WPF4.5, you can use BindingOperations.EnableCollectionSynchronization(collection, new object()); and it will marshal correctly. However, prior to WPF4.5, it's as Pavlo said.
Silverlight, WinRT: again the same as Pavol said.
Yes, collections. When you bind to an observable collection and you change it from a non-UI thread you will get an exception. You will have to marshal the collection change to the UI thread.
Related
I'm working on a project that utilizes WPF, using the Prism library and Unity Container.
I have a mainwindow, which contains a mainviewmodel control which in turn is populated by a collection of user controls.
My goal is to set keyboard focus to the mainviewmodel where I have an EventTrigger InvokeCommandAction which reacts to keyeventsargs...
Currently the only way the command is fired if I use a textbox within the control (or child controls). My goal is to have the mainviewmodel control or grid get and preserve keyboard focus.
Any tips would be appreciated!
//Nathan
Either not understanding your question correctly or you should review the basic concepts of MVVM in a WPF implementation.
The View is the WPF controls.
WPF Window/UserControl files contain WPF markup which is the View.
Controls in a view leverage DataBindings to the DataContext property of either the control itself or the parent containing control (which it will inherit).
DataContext property is set to an instance of an object that is the ViewModel. It contains properties to hold values and commands to execute actions.
So conceptually there is no "mainviewmodel control", there is a MainView which contains controls and may in this case have its DataContext property set to an instance o MainViewModel. (hence my confusion)
Finally, while it is possible and some might even recommend writing UI rules/logic in a view model I haven't found much benefit in it.
You are much better off putting UI logic in the XAML or in the MinView code behind. You can still access the MainViewModel in the code behind by casting the MainView.DataContext property as a MainViewModel.
So for example:
MainView.KeyDown event can be wired up to call MainViewModel.CommandX.Execute();
I use System.Windows.Controls.WebBrowser in my WPF, MVVM application.
I need to let ViewModel of WebBrowser know when Source property of WebBrowser changed, respectively when loaded html document changed. Of course, the best way is binding of Source property to ViewModel, but I found just this solution for binding, which provides only one-way binding from ViewModel to WebBrowser: databind the Source property of the WebBrowser in WPF
Old WebBrowser from namespace System.Windows.Forms has such a useful methods like "OnDocumentTitleChanged", but I can not find anything similar in System.Windows.Controls.WebBrowser.
Try listening to WebBrowser.Navigated & WebBrowser.Navigating and send a Message in code behind to you VM with the WebBrowser.Source and listen to it on your VM and process it unless you want to go hardcore MVVM, a EventToCommand on one of the 2 events are possible to.
I'm pretty new to wpf and mvvm so this may be a easy question but I'm hoping someone can explain it to me. I have a class in my model that all it does is polls processes and if it see that "calc" is running it adds it process id to a List. If you close calc.exe it removes it from the List. If the List changes it fires and event. In my ViewModel i subscribe to that event and update my property that fires off PropertyChanged. Now if my Property is a List in the view model then my binding in my view does not update correctly. If I changed my List to an ObservableCollection in my Model and ViewModel then i get a cross thread issue. However, if i leave my List in my model and change my property in my ViewModel to a ObservableCollection and copy the values of the the list into an observable collection everything works as expected.... I don't get it, do i really need to do the copy to get the binding in my ListBox to work properly?
Take a look at the DispatcherNotifiedObservableCollection that Cinch implements. It will automatically use the Dispatcher if need be. Read this article to see the code for it:
http://www.codeproject.com/KB/WPF/CinchIII.aspx#ObsCol
You need to update the observable collection from the dispatch thread.
Something like (not technically/syntactically correct, but psuedo-close)
Dispatcher.BeginInvoke( () => theList.Add( theThing ) );
A better way to achieve this functionality, is expose the Model via a property in the ViewModel, and bind the ListBox to Model.ObservableList. And use John's suggestion when adding and removing items to this list. This will not require you to copy the values from list to an observablecollection.
So your viewModel code would like
public class ViewModel
{
public Model Model { get { return _model; } }
}
The binding in xaml:
<ListBox ItemsSource=Model.ObservableList/>
where the ObservableList property returns your ObservableCollection.
As all UI elements in WPF have thread affinity (to the Dispatcher thread), any updates to the UI should be marshaled via the Dispatcher. You can marshal calls via the Dispatcher, using Dispatcher.Invoke. In this case, your view, viewModel and Model reside in the Dispatcher thread, so any call to update the UI via the viewModel or Model, would require you to call Dispatcher.Invoke.
I want to change a DependencyProperty of my ViewModel from a class which connects the application to a database.
This class raises events which should initiate a change of some properties in my ViewModel.
How can I realize that? I don't have the Dispatcher of the View.
I'm assuming you don't really have dependency properties on your viewmodels but rather normal C# properties which raises the PropertyChanged event.
If so, you should be fine already. Modify your properties from your background thread (normal concurrency issues apply obviously) and when they are bound to a WPF element's Dependency Property the runtime system will take care of marshalling the change to the proper thread (by using the view's Dispatcher object)
This works for normal properties, I'm not sure it works for ObservableCollections.
There are also different approaches for doing the marshalling inside the viewmodels. The simplest way is to just store the value of Dispatcher.CurrentDispatcher in your viewmodel's constructor. This works as long as your viewmodels are created on the UI thread.
One immediate solution to the problem is to capture the view's Dispatcher and store it on the view model when you create it, so you can Invoke/BeginInvoke the change to it in response to the event.
That being said, you should consider making your viewmodels use INotifyPropertyChanged with CLR properties rather than DependencyProperties to avoid issues like this. That way, any thread can make changes to your viewmodel and have the results reflected in the view.
I changed accidentally the value of a BusinessObject-property that implements INotifyPropertyChanged from within a BackgroundWorker (BackgroundWorker.DoWork).
Amazingly, this led not to an error but actualized the text of the TextBlock that was bound to the property without any complaint.
Is the execution of asynchronous bindings part of the WPF binding engine or is this only a special case where the CheckAccess-test have been forgotten or ommited due to other considerations.
Bindings on scalar properties support updates from other threads, so you don't need to call Dispatcher.Invoke when updating a property of the model (or ViewModel). However, this is not true for binding to a collection: if you have a ItemsControl bound to an ObservableCollection<T>, changes to this collection must be done on the UI thread, as CollectionChanged events are not automatically forwarded to the UI thread. Alternatively, you could use a variant of ObservableCollection<T> that raises the event on the UI thread (here's a implementation)