Binding failures when adding another property
I have a main view that binds to subviews like this (the backing property is of type object
):
<ContentControl Content="{Binding WalletsView}"/>
Now, I've added another property to the corresponding viewmodel, namely
public SmartObservableCollection<Selectable<Type>> PriceGrabbers {get; private set;}
where SmartObservableCollection
is derived from ObservableCollection
to make multithreaded updates easier.
Now I get a lot of binding errors (in fact, all bindings in the sub viewmodels run through the debug window) like this开发者_开发百科 (interestingly, if I remove the PriceGrabbers
property again, all errors disappear):
System.Windows.Data Error: 40 : BindingExpression path error: 'OverviewHidden' property not found on 'object' ''MainWindowViewModel' (HashCode=30986197)'. BindingExpression:Path=OverviewHidden; DataItem='MainWindowViewModel' (HashCode=30986197); target element is 'ColumnDefinition' (HashCode=22768693); target property is 'NoTarget' (type 'Object')
So the binding engine apperently tries to find any and all bindings on the main viewmodel. The bindings work perfectly fine. While this is okay, I'd rather have errors go away. Did anybody of you already encounter this problem, and if yes, how did you solve it?
The problem isn't with WPF but with my usage of MEF as composition container. The property modifies the import order of classes and the ViewModel coresponding to MainWIndow is assigned to all Views first, after which the correct one is assigned. When the data context is refreshed, all bindings are renewed, thus the application works.
edit and now I found the complete reason for it.
SmartObservableCollection
takes an Action<Action>>
parameter to execute on CollectionChanged
events, this is needed due to most of my collections getting updated in a multithreaded manner, but the events have to be executed in the GUI thread, otherwise you will get an exception.
For this, my Views expose Dispatcher.Invoke()
and Dispatcher.BeginInvoke()
as methods, which I then supply to the collection.
At startup, the DataContexts are assigned in the base class ViewModel
by the following lines:
Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate()
{
view.DataContext = this;
});
Who has an idea already?
The reason for this hickup was the simple fact I supplied the Dispatcher.Invoke()
method instead of Dispatcher.BeginInvoke()
to the collection. By doing this (and the fact it was used in the MainWindowViewModel
), it got executed before any DataContexts
got assigned to other ViewModels
.
Now, the next step occurs - the WPF engine tries to bind to the data in the sub views. As DataContext
is null
, the binding engine walks up the visual tree until it finds a set DataContext, in this case the first set DataContext is in MainWindowView
, and it is MainWindowViewModel
. Now, after the collection finished, all other actions get called and the DataContexts are assigned appropiately, thus reexecuting the binding engine which finds a non-null DataContext on the sub views and binds correctly.
精彩评论