Trying to Understand Dependency Properties
I have been trying to understand and get something working with dependency properties.
I have read loads of descriptions and explanations about DP's, and I also think I understand where they should be used.
I have read this and the links / references contain therein.
However, im still having problems. These maybe just mental blockages, maybe im clinging onto some idea or belief that i cant let go of.. anyway..
What im trying to do is create a control with a DP on it. Use that control in xaml and bind to the DP.
When i specify a value for the DP in the xaml the value is diaplayed on the user control as expected.
<DpTestProj:UserControl1 MyName="Steve"
However when i try to bind to it the value is not set, and i get
System.Windows.Data Error: 40 : BindingExpression path error: 'PersonName' property not found on 'object' ''UserControl1' (Name='')'. BindingExpre开发者_如何学运维ssion:Path=PersonName; DataItem='UserControl1' (Name=''); target element is 'UserControl1' (Name=''); target property is 'MyName' (type 'String')
Which suggests i have done something wrong with the binding or datacontext somewhere. But i cant see what.
My code is as follows.
UserControl1 has the following DP
public const string MyNamePropertyName = "MyName";
public string MyName
{
get
{
return (string)GetValue(MyNameProperty);
}
set
{
SetValue(MyNameProperty, value);
}
}
public static readonly DependencyProperty MyNameProperty = DependencyProperty.Register(
MyNamePropertyName,
typeof(string),
typeof(UserControl1),
new UIPropertyMetadata("No Name"));
Its used on the MainWindow like this
<StackPanel x:Name="LayoutRoot">
<DpTestProj:UserControl1 MyName="{Binding PersonName}" MyList="{Binding SomeListItems}" />
</StackPanel>
I'm using MVVM Light si the data context of the MainWindow is
DataContext="{Binding Main, Source={StaticResource Locator}}">
PersonName is a normal CLR (string) property that lives on the MainViewModel
If its easier I have posted the entire solution here
Your DependencyProperty isn't the issue here; the issue is the data you're binding it to. The binding isn't finding a property called Main.PersonName from whatever the Locator
resource is.
And the answer is...
you cant bind to the clr wrapper of a dp directly with a vanilla binding (even if you have set the dataContext of the userControl as this (i.e. the code behind of the userControl))
You can do one of two things to get changes to the dependency property reflected in the UI elements.
1) Use a RelativeSource Binding in FindAncestor mode
{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DpWrapperProp}"
2) Use the Dp's callback to update your UI element. (If youre using the callback to do some validation anyway, then this might be the route for you). Because the Callback is Static you need to create a non static method to do the update, and call that from the static method. The ui element (label textBlock whatever) also need to be named.
private static void ChangeText(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as MyUserControl).UpdateText(e.NewValue.ToString());
}
private void UpdateText(string newText)
{
MyLabel.Content = newText; //set the content of the named label
//defined in the userControl XAML
}
*the above examples are generic and not nesecarily related to my original code.
fyi i arrived at these solutons with the help of this and this
<DpTestProj:UserControl1 MyName="{Binding MyName}" ... />
?
Update:
Ok I took a closer look at your solution. In your UserControl1
you're basically overwriting your original DataContext.
To make things work, just remove that line:
public UserControl1() { InitializeComponent();DataContext = this;// this makes you lose your MainViewModel }
And edit your UserControl1.xaml
accordingly to bind to your original MainViewModel
:
<Label Content="{Binding PersonName}"/>
<ListBox ItemsSource="{Binding SomeListItems}" MinHeight="100" MinWidth="100"/>
Now I don't know your original scenario of why you wanted to set your UserControl1
's view model to itself. That's a very unusual way of doing things that is not very MVVM-like. If you really want to go that route, you'd have to create a new ViewModel that stores the original MainViewModel
in one property and the UserControl1
in another.
精彩评论