试图理解依赖属性

时间:2011-04-01 13:57:21

标签: .net dependency-properties

我一直在努力理解并使用依赖属性。

我已经阅读了大量关于DP的描述和解释,我也认为我理解应该在哪里使用它们。

我已阅读this,其中包含链接/参考。

然而,我仍然有问题。这些可能只是精神障碍,也许我坚持一些我无法放弃的想法或信念..无论如何..

我想要做的是创建一个带有DP的控件。 在xaml中使用该控件并绑定到DP。

当我在xaml中指定DP的值时,该值将按预期显示在用户控件上。

<DpTestProj:UserControl1 MyName="Steve"

然而,当我尝试绑定它时,没有设置值,我得到了

  

System.Windows.Data错误:40:BindingExpression路径错误:'object'''UserControl1'(Name ='')'上找不到'PersonName'属性。 BindingExpression:路径= PERSONNAME; DataItem ='UserControl1'(Name =''); target元素是'UserControl1'(Name =''); target属性是'MyName'(类型'String')

这表明我在某处绑定或datacontext做错了。 但是我看不清楚。

我的代码如下。

UserControl1具有以下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"));

它在MainWindow上使用就像这样

<StackPanel x:Name="LayoutRoot">
    <DpTestProj:UserControl1 MyName="{Binding PersonName}" MyList="{Binding SomeListItems}" />
</StackPanel>

我正在使用MVVM Light,MainWindow的数据上下文是

DataContext="{Binding Main, Source={StaticResource Locator}}">

PersonName是一个普通的CLR(字符串)属性,它存在于MainViewModel

如果我更容易发布整个解决方案here

3 个答案:

答案 0 :(得分:0)

你的DependencyProperty不是问题;问题是您将绑定到的数据。绑定不会从Locator资源中找到名为Main.PersonName的属性。

答案 1 :(得分:0)

答案是......

你不能直接用一个vanilla绑定绑定到dp的clr包装器(即使你已经将userControl的dataContext设置为这个(即userControl背后的代码))

您可以执行以下两项操作之一来更改UI元素中反映的依赖项属性。

1)在FindAncestor模式下使用RelativeSource绑定

{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DpWrapperProp}"

2)使用Dp的回调来更新UI元素。 (如果您使用回调进行某些验证,那么这可能是您的路线)。 因为回调是静态,所以您需要创建一个非静态方法来执行更新,并从静态方法中调用它。 ui元素(标签为textBlock)也需要命名。

    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
    }

*以上示例是通用的,与我的原始代码无关。

thisthis

的帮助下,我到达了这些解决方案

答案 2 :(得分:-1)

<DpTestProj:UserControl1 MyName="{Binding MyName}" ... />

<强>更新

好的,我仔细看了一下你的解决方案。在UserControl1中,您基本上会覆盖原始的DataContext。

为了使事情有效,只需删除该行:

    public UserControl1()
    {
        InitializeComponent();
        DataContext = this; // this makes you lose your MainViewModel
    }

然后相应地修改UserControl1.xaml以绑定到原始MainViewModel

<Label Content="{Binding PersonName}"/>
<ListBox ItemsSource="{Binding SomeListItems}" MinHeight="100" MinWidth="100"/>

现在我不知道您为什么要将UserControl1的视图模型设置为自己的原始场景。这是一种非常不寻常的做事方式,不像MVVM那样。如果您真的想要走这条路线,则必须创建一个新的ViewModel,将原始MainViewModel存储在一个属性中,将UserControl1存储在另一个属性中。