ViewModel中的DependencyProperty注册

joe*_*erg 5 wpf dependency-properties mvvm

我发现很多关于 ViewModels 及其属性的讨论比较了两种方法:INotifyPropertyChanged 的实现或通过Dependency Properties 的实现。

虽然我做了很多 INotifyPropertyChanged(并且它正在工作),但我在实施 DP 方法时遇到了困难。

当我像这样在 ViewModel 中注册 DP 时

    public static readonly DependencyProperty SomePropertyProperty =
        DependencyProperty.Register("SomeProperty", typeof(string), typeof(MyUserControl));
Run Code Online (Sandbox Code Playgroud)

并尝试在某处使用它:

<myNameSpace:MyUserControl SomeProperty="{Binding ...}"/>
Run Code Online (Sandbox Code Playgroud)

有一个编译器错误:

The property 'SomeProperty' does not exist in XML namespace 'clr-namespace:myNameSpace'.
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么??


编辑1

ViewModel 看起来像这样:

public class MyUserControlVM : DependencyObject
{

    public string SomeProperty
    {
        get { return (string)GetValue(SomePropertyProperty); }
        set { SetValue(SomePropertyProperty, value); }
    }

    public static readonly DependencyProperty SomePropertyProperty =
        DependencyProperty.Register("SomeProperty", typeof(string), typeof(MyUserControl));     
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*arc 5

您是否实现了标准属性访问器?完整的 DP 签名如下所示:

public static readonly DependencyProperty PropertyNameProperty =
        DependencyProperty.Register("propertyName", typeof (PropertyType), typeof (MyUserViewModel), new PropertyMetadata(default(PropertyType)));

    public PropertyType PropertyName
    {
        get { return (PropertyType) GetValue(PropertyNameProperty); }
        set { SetValue(PropertyNameProperty  value); }
    }
Run Code Online (Sandbox Code Playgroud)

那么你的代码应该可以工作。关于 DP 与 INotifyPropertyChanged 的​​更多信息:对我来说,主要的权衡是速度与可读性。用依赖属性声明乱扔你的 ViewModel 是一种痛苦,但你在通知管道中获得了大约 30% 的速度。

编辑:

您在 View 的类型上注册属性,它应该是 ViewModel 的类型,即

public static readonly DependencyProperty PropertyNameProperty =
        DependencyProperty.Register("propertyName", 
        typeof (PropertyType), 
        typeof (MyUserViewModel), 
        new PropertyMetadata(default(PropertyType)));
Run Code Online (Sandbox Code Playgroud)

代替

public static readonly DependencyProperty PropertyNameProperty =
        DependencyProperty.Register("propertyName", 
        typeof (PropertyType),
        typeof (MyUserControl), 
        new PropertyMetadata(default(PropertyType)));
Run Code Online (Sandbox Code Playgroud)

编辑2:

好的,您在这里混合了一些东西:您可以在 ViewModel 和 View 上都拥有依赖项属性。对于前者,您在控件的代码隐藏(即 MyUserControl.xaml.cs)中定义 DP。对于后者,您可以在 ViewModel 中定义它,如我上面所示。您的代码的问题在于用法:

你正试图绑定你的一些价值 DataContextSomeProperty 视图上调用的属性:

<myNameSpace:MyUserControl SomeProperty="{Binding SomePropertyBindingValue}"/>
Run Code Online (Sandbox Code Playgroud)

由于您在视图模型上定义了依赖项属性,因此视图上没有属性SomeProperty,因此您会收到编译器错误。要使上述用法起作用,您需要将 DP 放入View 的代码隐藏中,并SomePropertyBindingValue在 ViewModel 上定义一个普通属性。

要在 ViewModel 上定义 DP 并在视图中使用它,您需要绑定到此属性:

<myNameSpace:MyUserControl Width="{Binding SomeProperty}"/>
Run Code Online (Sandbox Code Playgroud)

假设您已正确连接 ViewModel 和 View,这会将视图宽度绑定到您的 ViewModel 的属性 SomeProperty。现在,如果SomeProperty在 ViewModel 上设置,UI 将更新,尽管您尚未实现 INPC。

编辑 3:

据我了解您的问题是 - 要获得所需的行为 - 您需要将控件上的一个依赖属性绑定到单独ViewModel上的两个属性:MainWindowVM上的一个属性应绑定到UserControl,然后 - 从UserControl -回到另一个ViewModel ( UserControl1VM )。这里的设计有点扭曲,在不知道确切上下文的情况下,我不明白为什么您不能在 ViewModel 级别处理属性同步:

我让我的 ViewModel 或多或少类似于视图的嵌套结构:

假设您有一个视图(伪代码):

<Window>
    <UserControl1 />
</Window>
Run Code Online (Sandbox Code Playgroud)

让窗口的数据上下文为MainWM,无论它来自哪里,这都不是正确的 XAML(!):

<Window DataContext="[MainVM]">
    <UserControl1 />
</Window>
Run Code Online (Sandbox Code Playgroud)

问题 1 是,为什么用户控件需要它自己的ViewModel?您可以简单地将其绑定到MainVM的属性“ SomeProperty ”:

<Window DataContext="[MainVM]">
    <UserControl Text="{Binding SomeProperty}" />
</Window>
Run Code Online (Sandbox Code Playgroud)

好吧,说你真的有充分的理由需要一个UserControlViewModel,它有它自己的属性“UCSomeProperty”:

<myNameSpace:MyUserControl SomeProperty="{Binding SomePropertyBindingValue}"/>
Run Code Online (Sandbox Code Playgroud)

UserControlVM属性添加到MainVM

<myNameSpace:MyUserControl Width="{Binding SomeProperty}"/>
Run Code Online (Sandbox Code Playgroud)

现在,您可以设置绑定:

<Window DataContext="[MainVM]">
    <UserControl DataContext="{Binding UserControlVM}" 
                 Text="{Binding UCSomeProperty}" />
</Window>
Run Code Online (Sandbox Code Playgroud)

最后,同样不知道您的具体情况以及它是否有意义,但假设您现在想要“MainVM”上的属性,该属性与用户控件的 ViewModel 属性上的属性同步:

<Window>
    <UserControl1 />
</Window>
Run Code Online (Sandbox Code Playgroud)

您可以像这样使用绑定,例如:

 <Window DataContext="[MainVM]">
    <UserControl DataContext="{Binding UserControlVM}" 
                 Text="{Binding UCSomeProperty}" />
    <TextBlock Text="{Binding SomeProperty}" />
</Window>
Run Code Online (Sandbox Code Playgroud)

MainVM上的SomePropertyUSerControlVM上的UCSomeProperty现在始终相同,并且在两个 ViewModel 上都可用。我希望这有帮助...

  • 好吧,我想我正在慢慢理解(但还没有完全理解,抱歉)。我认为我的理解问题在于控件和相应虚拟机的嵌套结构。我再试一次:我在此 MainWindow 中有 MainWindow 及其 DataContext MainWindowVM 和 UserControl1 及其 DataContext UserControl1VM。我想将 MainWindowVM 中的一个(普通)属性绑定到 UserControl1 上的 DP,该属性又绑定到 UserControl1VM 中的一个(普通)属性。我现在缺少的连接是 UserControl1 中的 DP 和 UserControl1VM 中的属性之间的连接。再次感谢!! (2认同)