你是否已经实现了标准属性访问器?一个完整的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); }
}
那么你的代码应该可以工作了。关于DP与INotifyPropertyChanged的更多信息:对我来说,主要的权衡是速度与可读性之间的平衡。在你的ViewModel中添加依赖属性声明可能会很麻烦,但你可以在通知管道中获得大约30%的速度提升。
编辑:
你应该在ViewModel的类型上注册属性,而不是View的类型。
public static readonly DependencyProperty PropertyNameProperty =
DependencyProperty.Register("propertyName",
typeof (PropertyType),
typeof (MyUserViewModel),
new PropertyMetadata(default(PropertyType)));
替代
public static readonly DependencyProperty PropertyNameProperty =
DependencyProperty.Register("propertyName",
typeof (PropertyType),
typeof (MyUserControl),
new PropertyMetadata(default(PropertyType)));
编辑2:
好的,你在这里混淆了一些东西:你可以在ViewModel和View上都有依赖属性。对于前者,在控件的代码后台(即MyUserControl.xaml.cs)中定义DP。而对于后者,你可以像我上面展示的那样在ViewModel中定义它。你代码的问题在于用法:
你试图将 DataContext
的某个值绑定到视图上的一个名为 SomeProperty
的属性上:
<myNameSpace:MyUserControl SomeProperty="{Binding SomePropertyBindingValue}"/>
由于您已在视图模型上定义了依赖属性,因此视图上没有SomeProperty
属性,因此会出现编译器错误。要使上述用法起作用,您需要将DP放在View的代码后面,并在ViewModel上定义一个普通属性SomePropertyBindingValue
。
要在ViewModel上定义DP并在视图中使用它,您需要将其绑定到此属性:
<myNameSpace:MyUserControl Width="{Binding SomeProperty}"/>
假设您已正确连接了ViewModel和View,这将将视图的宽度绑定到ViewModel的
SomeProperty
属性。现在,如果在ViewModel上设置了
SomeProperty
,UI将更新,尽管您尚未实现INPC。
编辑3:
据我所知,您的问题是为了获得所需的行为,您需要在
控件上绑定一个依赖属性到两个独立的 ViewModel 上的属性:一个属性在 MainWindowVM 上应该绑定到 UserControl ,然后从 UserControl 返回至另一个 ViewModel ( UserControl1VM )。 这里的设计有点扭曲,并且不知道确切的上下文,我不明白为什么您不能在ViewModel级别处理属性同步:
我让我的ViewModels更或多或少地类似于View的嵌套结构:
假设您有一个视图(伪代码):
<Window>
<UserControl1 />
</Window>
将窗口的数据上下文设为MainWM,无论数据来自何处,这都不是正确的XAML写法(!):
<Window DataContext="[MainVM]">
<UserControl1 />
</Window>
第一个问题是,为什么用户控件需要有自己的ViewModel?你可以简单地将其绑定到MainVM的属性“SomeProperty”:
<Window DataContext="[MainVM]">
<UserControl Text="{Binding SomeProperty}" />
</Window>
好的,假设你有一个充分的理由需要一个UserControlViewModel,并且它有自己的属性'UCSomeProperty':
public class UserControlVM
{
public string UCSomeProperty { get; set; }
}
在 MainVM 中添加一个 UserControlVM 属性:
public class MainVM
{
public UserControlVM UserControlVM { get; set; }
}
现在,您可以设置绑定:
<Window DataContext="[MainVM]">
<UserControl DataContext="{Binding UserControlVM}"
Text="{Binding UCSomeProperty}" />
</Window>
最后,假设你现在想让'MainVM'上的属性与用户控件的ViewModel属性同步,但不了解你具体的情况和是否有意义。
public class MainVM
{
public string SomeProperty
{
get { return UserControlVM.UCSomeProperty; }
set { UserControlVM.UCSomeProperty = value; }
}
public UserControlVM UserControlVM { get; set; }
public MainVM()
{
UserControlVM = new UserControlVM();
UserControlVM.NotifyPropertyChanged += UserControlVM_PropertyChanged;
}
private void UserControlVM_PropertyChanged(object sender, BlaArgs e)
{
if (e.PropertyName == "UCSomeProperty")
RaisePropertyChanged("SomeProperty");
}
}
例如,您可以像这样使用绑定:
<Window DataContext="[MainVM]">
<UserControl DataContext="{Binding UserControlVM}"
Text="{Binding UCSomeProperty}" />
<TextBlock Text="{Binding SomeProperty}" />
</Window>
现在,在MainVM上的SomeProperty和在UserControlVM上的UCSomeProperty始终相同,并且两个ViewModel中都可以使用。希望这能帮到您...
Register
调用中的第三个参数指定,必须是声明该属性的类型。这里是MyUserControlVM
,而不是MyUserControl
。 - Clemens