Binding failures when adding another property - wpf

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.

Related

Is dependency property same as a CLR property which emits a PropertyChanged event as callback?

The question is related to WPF Data Binding and MVVM pattern.
I am bit confused now distinguishing between the Dependency property defined in the XAML.cs file as well as a CLR property defined in the view model which is bound to some property of a component
For example say, I have a textbox in MyPage.xaml. So I created a dependency property to bind the textbox text property in the MyPage.xaml.cs maybe some String. The next time, I created a viewModel MyPageViewModel.cs which implements the INotifyPropertyChanged interface and
created a CLR property there(String), which emits an event PropertyChanged when it changes or the property is set with a new value. So are these both the same? Is there any difference?
I have 3 questions
Is the Dependency Property same as CLR property which emits a PropertyChanged event when it changes?
Whether Dependency property is written in the view itself(MyPage.xaml.cs) or can it be included in the view
model(MyPageViewModel.cs)?
In MVVM pattern, we use the CLR properties more which emits an event during property change. So can dependency property be replaced
by such kind of CLR properties?
Thanks in advance.
An dependency property is on a DependencyObject from which all WPF UI elements derive from (and only works there), as it's static and saves it's value in a kind of collection assigned to a specific DependencyObject (on which the dependency property is defined). Dependency properties can be defined in a class outside of the actual DependencyObject to extend it's functionality without modifying the original user control class.
When you write a user control and want a ViewModel to allow to bind a value and receive notifications when it's changed, then you create a dependency property.
Imagine it like an USB cable, where you have a male plug and a female receptacle. The CLR property is like the plug and the dependency property is like the receptacle.
A dependency property allows you to store that's associated with a control but isn't part of the instance. As you can see on the MSDN Examples
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(Boolean),
...
);
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
the dependency property is static and GetValue and SetValue are methods of DependencyObject (base class on which all WPF UI elements are based on).
Depencency Properties (and attached properties/attached behavior) can also be used to extend the functionality of a UserControl without inheriting from the actual user control type, i.e. notifying the ViewModel when a certain value changes which is not provided by the original user control.
Is the Dependency Property same as CLR property which emits a PropertyChanged event when it changes?
No, it's not the same. They are both 2 sides of the databinding engine. A DP is defined on the view to allow a view model to bind a INPC Property (Property that rises PropertyChanged event)
Whether Dependency property is written in the view itself(MyPage.xaml.cs) or can it be included in the view model(MyPageViewModel.cs)?
DP are part of the View-Layer as they depend on DependencyObject, which is part of the WPF framework and hence view concern. While technically nothing prevents you from using them in the ViewModel, this causes a tight coupling of your ViewModel towards a certain View technology, so it doesn't fully comply MVVM pattern.
Be aware though that unit testing Dependency Properties may be quite difficult as they don't store the values on the class they are defined on but in some kind of dictionary where the GetValue/SetValue methods warp around.
Last but not least, since DependencyObject is the base class of all UI it is as well as most of the classes that derive from it thread affine, which means you can only access it from the thread you created which may cause you much pain in both unit test (especially if the tests run in parallel like MSTest used to do. Dunno if its still true as of today) and in your code.
In MVVM pattern, we use the CLR properties more which emits an event during property change. So can dependency property be replaced by such kind of CLR properties?
In ViewModels you could and you should use INotifyPropertyChanged. If you are developing a user control, you shouldn't replace DPs with "CLR" properties, because this makes the property not work with databinding in XAML.
If your UI elements should expose a property which can be used with data binding you have to use dependency properties (or attached properties which are pretty similar, but you place attached properties on i.e. the child elements. Grid.Row and Grid.Column are examples of attached properties).

How to avoid the '[Unknown]' property does not point to a DependencyObject in path '(0).(1)[1].(2)' exception in wpf

On button click, Updating the ListBox ItemsSource collection.
For 4 or 5 clicks its working fine but afterwards it throws an exception as '[Unknown]' property does not point to a DependencyObject in path '(0).(1)[1].(2)'
I googled it & find the reason for it.
"The ElementControl overrides PrepareContainerForItemOverride and
calls PrepareModel to insert a mesh into _modelContainer for each
Item. Later in ElementFlow.BuildTargetPropertyPath (which is called
via ElementFlow.SelectItemCore -> LayoutBase.SelectElement ->
ElementFlow.PrepareTemplateStoryboard) it is assumed that such a mesh
has been inserted into _modelContainer. This exception occurs when the
mesh has not been inserted into _modelContainer. WPF calls
PrepareContainerForItemOverride on ApplyTemplate. This is only done
once. Items added later are never processed like that. "
So please provide me a solution to overcome it.
It seems like maybe there is an item in your " itemsource collection" that is not of the right type, or does not contain one of the properties that your listbox itemstemplate is looking for. Or, perhaps if you have different classes in your collection, one of them may not have the property you are looking for as a DependencyProperty. If it is just a plain property, it may not work correctly.
Check all object types that are going into your itemssource collection and make sure they all have DependencyProperties that are named what the itemstemplate is looking for.

How to Delay XAML Binding until after Loaded

Look at this:
<ItemsControl ItemsSource="{x:Static local:Cache.Colors}" />
This binds the ItemsControl to a static property called List. In this case, the Colors property is part of a class called Cache.
But there is a problem. When you bind in this way, the Colors property is called during the Initialize method, prior to when Security is established in the application.
Because Security has not been established, then calling Colors results in an exception as Security is a requirement for successfully calling the data service.
The solution moves this from XAML to code behind and ensures it is executed in the Loaded event instead of in the constructor during Initialize.
The real problem here is, I would like to do this in XAML. Is it possible?
I have typically solved this by having the ItemsSource being bound to implement the INotifyCollectionChanged interface. At initialization the items source would be empty, and then at load time the items source is populated. The population of the items source raises the collection changed event, causing your items control to rebind/add the new items in the source.
My solution was to run it in the App.xaml.cs before anything else.

WPF: Proper configuration for Window with a child UserControl (MVVM)

I am trying to properly accomplish the following. I have a UserControl (ProgramView). It has a viewmodel (ProgramViewViewModel). ProgramView is consumed as a child control within a Window (ProgramWindow). ProgramWindow has a public property ProgramId, so the consumer of the window can specify the desired Program (data entity) to show. ProgramView has a property ProgramId, as it's primary job is to display this data. ProgramWindow is little more than a wrapper window for this user control.
ProgramViewViewModel also has a property ProgramId. Changes to this property drive out the operation of the view model, which are surfaced out of the view model using other properties, which ProgramView can bind to.
I am trying to hide the operation of the view model from the consumer of the ProgramView and ProgramWindow.
This ProgramId should be bound through all of these layers. Changes to ProgramWindow.ProgramId should flow to ProgramView.ProgramId and then to ProgramViewViewModel.ProgramId. I cannot figure out how to properly implement this.
My current approach is to surface ProgramId in all three classes as a DP. Within the Window, I would imagine ProgramView being instantiated thusly:
<local:ProgramView ProgramId="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProgramWindow}}, Path=ProgramId}" />
This appears to actually work. Within ProgramView, I do obtain changed events for the property, and they do appear to have the correct value. FindAncestor seems to operate properly.
How then should I synchronize the ProgramViewViewModel.ProgramId property? I see two ways. One way would be to set a Binding on the ProgramViewViewModel instance itself, to also use FindAncestor, and find the ProgramId on the ProgramViewViewModel This has two downsides. It requires ProgramViewViewModel to surface ProgramId as a dependency property. I'd rather like to avoid this, but it might be acceptable. Either way, I cannot accomplish it in XAML.
<local:View.DataContext>
<local:ProgramViewViewModel
ProgramId="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ProgramView}}, Path=ProgramId}" />
</local:View.DataContext>
This does not work. It appears that I cannot introduce a binding expression within the instantiation of the instance. FindAncestor reports that it cannot find ProgramView. My theory here is that the instance is outside of the logical tree, and thus cannot traverse to it's parent.
The second option, which makes more sense, is to bind the ProgramView.ProgramId property to "ProgramId" (in the DataContext). I cannot accomplish this because I cannot figure out how to specify a binding expression on a property defined in the code-behind. is required in the XAML, but the type ProgramId exists on is actually . I cannot figure out how to specify this property.
If I manually (in code-behind of ProgramView) create a Binding instance and call SetBinding(ProgramIdProperty, binding), the value no longer flows into the View itself. I believe this is because I just replaced the binding on ProgramView.ProgramId, which was previously set by ProgramWindow. One binding per-property?
My remaining ideas are to provide TWO ProgramId properties in ProgramView. One bound to the DataContext, the other publicly available to be bound by the consumer (ProgramWindow), and then write OnValueChanged handlers that synchronize the two. This feels like a hack. The other is to manually watch for changes on ProgramView.ProgramId and ProgramView.DataContext within the code-behind of ProgramView, and propagate the value myself. Neither of these ideas feel ideal.
I'm looking for other suggestions.
Your description seems detailed but I'm having trouble understanding why you need to implement this design. I can't help but think DRY.
If you need to expose a dependency property in two such-related view models, I would suggest that you make the child view model (for the user control view) a property of the first (for the program window view). Something like:
public class MainViewModel : ViewModelBase
{
public ProgramViewModel ChildViewModel { get; private set; }
}
public class ProgramViewModel : ViewModelBase
{
private int _ProgramId;
public int ProgramId
{
get { return _ProgramId; }
set
{
if (value != _ProgramId)
{
// set and raise propery changed notification
}
}
}
}
The MainView can get the property using ChildViewModel.ProgramId (data context set to MainViewModel). The ProgramView accesses it by ProgramId (data context set to MainViewModel.ChildViewModel).

DataContext, DataBinding and Element Binding in Silverlight

I'm having one hell of a time trying to get my databinding to work correctly. I have reason to believe that what I'm trying to accomplish can't be done, but we'll see what answers I get.
I've got a UserControl. This UserControl contains nothing more than a button. Now within the code behind, I've got a property name IsBookmarked. When IsBookmarked is set, code is run that animates the look of the button. The idea is that you click the button and it visually changes. We'll call this UserControl a Bookmark control.
Now I have another control, which we'll call the FormControl. My FormControl contains a child Bookmark control. I've tried to do databinding on my Bookmark control, but it's not working. Here's some code to help you out.
This is the XAML and Loaded event handler of my control. As you can see it contains a child element that is a custom control (bookmark). So once this control loads, it's DataContext is set to an new instance of an Employee object. Silverlight also sets the DataContext property of my child bookmark control to the same instance. I've verified this by debugging. If my parent has a valid DataContext set then why can't my child control (bookmark) property databind to it?
<UserControl ......>
<q:Bookmark x:Name="BookMarkControl1" IsBookmarked="{Binding IsSiteBookmarked}" />
</UserControl>
public void Control_Loaded(object sender, EventArgs e)
{
DataContext = new Employee { IsSiteBookmarked = True };
}
This is my custom control below. Obviously it contains more than this, but for readability I've trimmed it down to the property I'm trying to databind to.
//this is the bookmark control. I've included this control within another control, and I'm trying to databind to properties within my parents DataContext
public partial class Bookmark : UserControl
{
bool _IsBookmarked= false;
public bool IsBookmarked
{
get {return _IsBookmarked;}
set {
_IsBookmarked= value;
SwitchMode(value);
}
}
}
UPDATE
Got some javascript errors that I should mention. Firebug reports a AG_E_PARSER_BAD_PROPERTY_VALUE exception. It doesn't seem like my databinding is even working yet.
Make your IsBookmarked property on the Bookmark control a dependency property.
I presume Control_Loaded is a part of your FormControl, in which case I'm not sure you are using DataContext properly. Best double check that.
UPDATE: Yes, you are using the DataContext properly. AG_E_PARSER_BAD_PROPERTY_VALUE indicates you need to make the IsBookmarked property a dependency property, like so:
Public Property IsBookmarked() As Boolean
Get
Return Me.GetValue(IsBookmarkedProperty)
End Get
Set(ByVal value As Boolean)
Me.SetValue(IsBookmarkedProperty, value)
End Set
End Property
Public Shared ReadOnly IsBookmarkedProperty As DependencyProperty = DependencyProperty.Register("IsBookmarked", GetType(Boolean), GetType(Bookmark), New PropertyMetadata(New PropertyChangedCallback(AddressOf OnIsBookmarkedPropertyChanged)))
Private Shared Sub OnIsBookmarkedPropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
Dim cntrl As Bookmark = TryCast(d, Bookmark)
cntrl.SetIsBookmarked(e.NewValue)
End Sub
If you only need to store the value for later use, then you don't need to do anything in the OnIsBookmarkedPropertyChanged procedure, But I put some code there as an example anyway.
Good Luck!
I don't recall the exact order in which databinding is evaluated (and I'm too lazy to go look it up), but as I recall, it initially happens BEFORE the form's Loaded event fires, and without making the IsBookmarked property a dependency property, or at least using INotifyPropertyChanged, it may have trouble establishing the datacontext appropriately. I'd recommend either implementing INotifyPropertyChanged or making IsBookmarked a dependency property. DataBinding is tough enough to get right in the best of circumstances (see my long, bad-tempered rant about it here), and you'll just be making it more difficult on yourself if you aren't setting up your properties in the way that it expects.
The control exposes a IsSiteBookmarked property(which I believe should be a DependencyProperty) but the control is binding to a IsBookmarked which is not shown. Is this intentional? Have you checked your Visual Studio output window for binding errors?
Addition 1:
Since you have fixed the typo in your question and added that there is an error being reported.
Start by clearing up the AG_E_PARSER_BAD_PROPERTY_VALUE problem. Is there a line number and start position in the error message? Start looking there. One strategy is to start taking out XAML until there is no longer an error. This will narrow down the offending code.
Running in debug, mode check for binding errors in the output window.
You might want to also post the Employee class code, especially the IsSiteBookmarked property.
Typically when doing databinding to an object you will want to leverage the INotifyPropertyChanged interface and implement that so that the control can properly invalidate it's property value. Unless you use INotifyPropertyChanged with Mode=TwoWay then any code that changes your DataContext's IsSiteBookmarked will have no effect.

Resources