What is the DataContext of a DependencyObject in Silverlight4? - silverlight

I have read that SL4 introduces the ability to data bind properties on objects that derive from DependencyObjects, where previously data-binding only worked on FrameworkElements or FrameworkContentElements.
However, I am not clear on how the binding source is determined when binding properties of DependencyObjects.
In the case of FrameworkElements, the element's DataContext property is the source object ('walking up the tree' to find a DataContext, if the DataContext isn't set directly).
In the case of DependencyObjects, I would guess that the DataContext used is the DataContext of the 'containing' FrameworkElement in the XAML file. But what is the mechanism for determining this containing object?
In my particular case, I am trying to bind the property of a DependencyObject that lives in an ObservableCollection that is a property of a FrameworkElement. Unfortunately attempting to bind the property on the DependencyObject fails, as the databinding system appears to be using the DependencyObject itself as its own DataContext. It complains (in the output window) that the type does not have a property with the name specified in the binding expression. Binding a dependency property of a FrameworkElement in the same UserControl with the same binding expression is successful.

Have you tried stating the Source or ElementName property when defining the Binding?
(e.g: {Binding Source={StaticResource theFrameworkElement} Path=theObservableCollection[0]}
or {Binding ElementName=theFrameworkElement Path=theObservableCollection[0]}

Related

WPF Static Resource

I'm trying to bind a string in the Window resources to a property.
I know that that binding works on dependency properties.
Does the string class in WPF have a dependency property?
Thank you
<Window.Resources>
<sys:String x:Key="strWindow"> Content= myProperty </sys:String>
</Window.Resources>
If you are exploring, then all I can say is that no one does it this way.
As for your question, string class does not dependency property of any kind. Only subclasses of DependencyObject class can have DependencyProperty. All WPF controls are subclasses of DependencyObject, and most of the properties we commonly access are coded as dependency property.
For example, TextBox is a subclass of DependencyObject, and has a Text property coded as a dependency property.
Do note that you can also build your own custom controls (by subclassing from FrameworkElement or one of its subclass), and write your own properties. If you don't code the property as a dependency property, that property will not be bindable.

WPF MVVM binding error

I'm using the MVVM pattern. In my ViewModel I have a public ObservableCollection:
public ObservableCollection<SettingsTemplateHistoryItemViewModel> HistoryItemCollection;
public SettingsTemplateViewModel()
{
this.HistoryItemCollection = new ObservableCollection<SettingsTemplateHistoryItemViewModel>();
}
In my View I have an ItemsControl with its ItemsSource property bound to the ObservableCollection in the ViewModel.
<ItemsControl ItemsSource="{Binding HistoryItemCollection}"/>
I'm getting the following error:
BindingExpression path error: 'HistoryItemCollection' property not found on 'object' ''SettingsTemplateViewModel' (HashCode=48413709)'. BindingExpression:Path=HistoryItemCollection; DataItem='SettingsTemplateViewModel' (HashCode=48413709); target element is 'ItemsControl' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')
I'm baffled. I am 100% certain the property exists in the View's DataContext (i.e. the ViewModel). I've copied and pasted the property name into the View, so the binding path must be correct. The View and the ViewModel are wired up via implicit/typed DataTemplates. What am I missing?
like the binding error says, your datacontext for your itemscontrol does not contain a public property called HistoryItemCollection. an easy way to check the datacontext at runtime is using Snoop
EDIT: you have to use a property instead of a field.
public ObservableCollection<SettingsTemplateHistoryItemViewModel> HistoryItemCollection {get;set;}

Error binding a dependency property of a user control to a property on the parent's view model

I have a user control that contains three checkboxes and three date pickers. For example, one of the date pickers on the user control looks like this (irrelevant properties like Width, etc removed for clarity)...
<telerik:RadDatePicker DisplayFormat="Long"
SelectedValue="{Binding DepositPaidDate, Mode=TwoWay}"/>
The view model for the control has a public property called PaidDate that is of type PaidDate (yup, the property and the class have the same name), the top-level Grid on the control has its DataContext set to the PaidDate property, and the individual controls in the Grid are bound to properties on this PaidDate object.
When this control is used on a window, and the window's code behind sets the PaidDate property on the control's VM explicitly, it all works fine. For example, I created a test window, whose constructor looked like this...
public PaidDateWindow(PaidDate paidDate, string windowTitle) {
InitializeComponent();
((PaidDateControlViewModel)PaidDateCtrl.DataContext).PaidDate = paidDate;
Title = windowTitle;
}
...and this worked just fine. I could show the window, and the data was displayed correctly.
The problem comes when I try to set this via a dependency property on the control. The dependency property in the user control's code behind looks like this...
public static readonly DependencyProperty PaidDateProperty = DependencyProperty.Register("PaidDate", typeof(PaidDate), typeof(PaidDateControl), new FrameworkPropertyMetadata(SetPaidDateStatic));
private static void SetPaidDateStatic(DependencyObject d, DependencyPropertyChangedEventArgs e) {
(d as PaidDateControl).SetPaidDate((PaidDate)e.NewValue);
}
private void SetPaidDate(PaidDate paidDate) {
if (DataContext != null) {
((PaidDateControlViewModel)DataContext).PaidDate = paidDate;
}
}
public PaidDate PaidDate {
get {
return (PaidDate)GetValue(PaidDateProperty);
}
set {
SetValue(PaidDateProperty, value);
}
}
As you can see, the dependency property just passes the PaidDate object through to the view model, which has the same effect as when I did this manually in the previous bit of code.
When I try to bind this dependency property to a property on the window's view model, I get a binding error. Here is the XAML in the parent window...
<vrtSystemsUserControls:PaidDateControl
PaidDate="{Binding Path=VRTSystem.PaidDate, Mode=TwoWay}" />
The parent window's VM contains a property called VrtSystem, and plenty of other controls on the window are bound to properties on that. VrtSystem also contains a property called PaidDate, and that is what I want to pass to the user control.
However, when I run this, I get the following binding error...
System.Windows.Data Error: 40 : BindingExpression path error:
'VRTSystem' property not found on 'object' ''PaidDateControlViewModel' (HashCode=18319327)'.
BindingExpression:Path=VRTSystem.PaidDate; DataItem='PaidDateControlViewModel' (HashCode=18319327);
target element is 'PaidDateControl' (Name=''); target property is 'PaidDate' (type 'PaidDate')
Now it looks to me as though WPF is passing the actual binding information through to the user control, instead of the PaidDate object, as the error says it is trying to find a VrtSystem property on the user control's VM. I have no idea why it would be doing that, as I thought the idea of the binding was to resolve the binding at the window level, and then send the results (ie the PaidDate object) in to the dependency property, where it would be sent to the VM.
I hope I've explained this clearly. Anyone able to see what's gone wrong?
Thanks for any help.
When your binding is being resolved, it is looking for the VRTSystem property on the DataContext of the control it is being applied to.
The 'DataContext' property is being inherited by child-controls so if you set a DataContext on a Window all of its children will have the same DataContext. If however one of the children itself has a different DataContext applied, all of its children will use that.
In your case, the Window has a DataContext, but so has the UserControl. So by default all bindings on the UserControl or it's chilren, will expect to find the VRTSystem property on the UserControls DataContext which is not what you want in this case.
So to explicitly target the DataContext of the Window, you have to tell the binding, by setting its RelativeSource property like this:
{Binding Path=DataContext.VRTSystem.PaidDate, Mode=TwoWay,
RelativeSource={RelativeSource AncestorType={x:Type Window}}}

Inject ViewModel property as ValueConverter

All ValueConverter examples I have found used Resources to create ValueConverter instance. But my ValueConverter uses some dependencies which are resolved by IoC framework. So I would like to set Binding Converter property to some property of my ViewModel which is accessible through DataContext. I tried to do it but got an exception telling I can't bind anything to Converter property of binding.
You cannot bind Binding.Converter as it is not a dependency property, but you can make the converter inherit from DependencyObject and declare dependency properties on that instead, then you can bind those.
Note however that you might need to jump some hoops to get what you want as you will not be able to bind to the DataContext. You probably cannot use ElementName either because the converter will have no name-scope. One common workaround is to target an object with the right DataContext using Binding.Source with x:Reference. Make sure not to declare to instantiate the converter inside the visual tree of the targeted object or x:Reference will throw cyclical dependency errors (the targeted object's Resources are fine).

How can I bind from a user control to an external object in XAML?

I have an image inside a user control that I want to bind it's visibility to a property I have set up in a class object. The dependency properties are set up and working correctly, but I don't know how to set the binding properly on the image.
The user control and class object are in the same namespace. I thought I would need to set the ElementName to the window or the RelativeSource to the class object, but I'm not getting it to work out.
Here's what a dependency property looks like (defined in MigrateUserWizardObject.cs, this inherits from DependencyObject, this resides in the UserAccountMigrator namespace):
public static readonly DependencyProperty DatabaseStepCompletedVisibilityProperty = DependencyProperty.Register("DatabaseStepCompletedVisibility", typeof(Visibility), typeof(MigrateUserWizardObject));
public Visibility DatabaseStepCompletedVisibility
{
get
{
return (Visibility)GetValue(DatabaseStepCompletedVisibilityProperty);
}
set
{
SetValue(DatabaseStepCompletedVisibilityProperty, value);
}
}
Here's an image that I want bound to this dependency property (defined in ProgressUserControl.xaml, this inherits from UserControl, this resides in the UserAccountMigrator namespace as well):
<Image x:Name="DatabaseCompleted" Source="{StaticResource GreenCheckMarkSource}" Visibility="{Binding Path=DatabaseStepCompletedVisibility, UpdateSourceTrigger=PropertyChanged}" Height="20" HorizontalAlignment="Right"></Image>
This is due to the fact that the DataContext of the image is the user control. How can I make this work?
I think you should look into using the Model-View-ViewModel pattern. Instead of setting the DataContext to the UserControl, set it to an instance of another class (ProgressViewModel, for example). This view model would have all the properties you want to bind to (including your DatabaseStepCompletedVisibility property) and makes it much easier. Right now you are wanting to bind some things to the UserControl, some things to another object somewhere else, etc.. and, as you have found, makes it difficult. Here is more information:
http://jmorrill.hjtcentral.com/Home/tabid/428/EntryId/432/MVVM-for-Tarded-Folks-Like-Me-or-MVVM-and-What-it-Means-to-Me.aspx
Without going that approach, you have to have an instance MigrateUserWizardObject to bind to. You can put that instance in your UserControl (if you insist on using it as the DataContext), then you can bind the the property of the MigrateUserWizardObject property of the UserControl. Also, your MigrateUserWizardObject doesn't have to be a dependency object or dependency property to bind to. A better pattern would be to make it a plain c# class that implements the INotifyPropertyChanged interface.

Resources