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)
您是否实现了标准属性访问器?完整的 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 中定义它,如我上面所示。您的代码的问题在于用法:
你正试图绑定你的一些价值 DataContext到SomeProperty
视图上调用的属性:
<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上的SomeProperty和USerControlVM上的UCSomeProperty现在始终相同,并且在两个 ViewModel 上都可用。我希望这有帮助...
| 归档时间: |
|
| 查看次数: |
10672 次 |
| 最近记录: |