DependencyProperty 绑定模式为双向但 propertychangedeventhandler 为 null
我尝试使用 C# 和 XAML 遵循 MVVM 设计范例。我在嵌套用户控件方面遇到了麻烦。我试图将嵌套用户控件上的元素绑定到 ViewModel 中的值之一(通过 DataContext 属性绑定到 View)。相同的 ViewModel 用于外部和嵌套用户控件。
它部分按原样工作,但更改仅从 ViewModel 到嵌套用户控件进行单向。我需要在嵌套用户控件中所做的更改传播回 ViewModel。
从主视图的 XAML 开始,我有:
<UserControl>
<!-- ... -->
<UserControl.DataContext>
<local:MyViewModel x:Name="myViewModel" />
</UserControl.DataContext>
<!-- ... -->
<local:NestedUserControl
x:Name="nestedUserControl"
CustomNestedValue="{Binding Path=CustomValue, ElementName=myViewModel, Mode=TwoWay}" />
</UserControl>
在 ViewModel 的 C# 代码中:
// Constructor
public MyViewModel()
{
CustomValue = true;
}
private bool _customValue;
public bool CustomValue
{
get { return _customValue; }
set
{
if (_customValue != value)
{
_customValue = value;
RaisePropertyChanged ("CustomValue");
}
}
}
在 NestedUserControl
的后面的代码中,我有:
public static readonly DependencyProperty CustomNestedValueProperty =
DependencyProperty.Register (
"CustomNestedValue",
typeof (bool),
typeof (NestedUserControl),
new FrameworkPropertyMetatdata
{
BindsTwoWayByDefault = true,
PropertyChangedCallback =
new PropertyChangedCallback (CustomNestedValueChangedCallback)
});
public bool CustomNestedValue
{
get { return (bool) GetValue (CustomNestedValueProperty); }
set { SetValue (CustomNestedValueProperty, value); }
}
protected static void CustomNestedValueChangedCallback (
DependencyObject Source,
DependencyPropertyChangedEventArgs e)
{
bool value = (bool) e.NewValue;
NestedUserControl control = source as NestedUserControl;
control.OnCustomValueChange (value);
}
public void OnCustomValueChange (bool value)
{
RaisePropertyChanged ("CustomNestedValue");
// Do other stuff ...
}
// This function is where the nested user control gets direct
// interactions from the user which cause the dependency
// property to change. When this event occurs, the change needs
// to be communicated back up to the view model.
private void _onPreviewMouseDown (object sender, MouseButtonEventArgs e)
{
CustomNestedValue = !CustomNestedValue;
}
[注意:我不仅设置在 XAML 中设置绑定时,绑定模式为 TwoWay,但我尝试将其设置为上面代码中 DependencyProperty 的默认行为。 ]
嵌套用户控件的代码和 ViewModel 代码都包含以下 PropertyChangedEventHandler
事件/响应,这是 INotifyPropertyChanged
接口所必需的。据我了解,这就是 XAML 元素和 ViewModel 之间的绑定保持同步的方式。
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
try
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
catch (Exception e)
{
// ...
}
}
当我运行代码时,每当为 NestedUserControl
调用 RaisePropertyChanged
函数时,PropertyChanged
事件始终为 null 。这只是嵌套用户控件的问题,而不是外部用户控件的问题。这个事件不应该通过绑定机制自动设置吗?
我已经为此苦苦挣扎好几天了,但毫无结果。任何帮助将不胜感激。谢谢!
I'm trying to follow the MVVM design paradigm with C# and XAML. I'm running into trouble with a nested user control. I'm trying to bind an element on the nested user control to one of the values in the ViewModel (which is bound to the View via the DataContext property). The same ViewModel is used for both the outer and nested user controls.
It partially works as is, but changes only go one-way from the ViewModel to the nested user control. I need the changes made in the nested user control to propagate back to the ViewModel.
Starting with the XAML for the main View, I have:
<UserControl>
<!-- ... -->
<UserControl.DataContext>
<local:MyViewModel x:Name="myViewModel" />
</UserControl.DataContext>
<!-- ... -->
<local:NestedUserControl
x:Name="nestedUserControl"
CustomNestedValue="{Binding Path=CustomValue, ElementName=myViewModel, Mode=TwoWay}" />
</UserControl>
In the C# code for the ViewModel:
// Constructor
public MyViewModel()
{
CustomValue = true;
}
private bool _customValue;
public bool CustomValue
{
get { return _customValue; }
set
{
if (_customValue != value)
{
_customValue = value;
RaisePropertyChanged ("CustomValue");
}
}
}
And in the code behind of the NestedUserControl
, I have:
public static readonly DependencyProperty CustomNestedValueProperty =
DependencyProperty.Register (
"CustomNestedValue",
typeof (bool),
typeof (NestedUserControl),
new FrameworkPropertyMetatdata
{
BindsTwoWayByDefault = true,
PropertyChangedCallback =
new PropertyChangedCallback (CustomNestedValueChangedCallback)
});
public bool CustomNestedValue
{
get { return (bool) GetValue (CustomNestedValueProperty); }
set { SetValue (CustomNestedValueProperty, value); }
}
protected static void CustomNestedValueChangedCallback (
DependencyObject Source,
DependencyPropertyChangedEventArgs e)
{
bool value = (bool) e.NewValue;
NestedUserControl control = source as NestedUserControl;
control.OnCustomValueChange (value);
}
public void OnCustomValueChange (bool value)
{
RaisePropertyChanged ("CustomNestedValue");
// Do other stuff ...
}
// This function is where the nested user control gets direct
// interactions from the user which cause the dependency
// property to change. When this event occurs, the change needs
// to be communicated back up to the view model.
private void _onPreviewMouseDown (object sender, MouseButtonEventArgs e)
{
CustomNestedValue = !CustomNestedValue;
}
[Note: Not only do I set the binding mode to TwoWay when setting the binding in XAML, but I attempted to make this the default behavior of the DependencyProperty in the code above. No luck.]
Both the code behind for the nested user control and the ViewModel code contain the below PropertyChangedEventHandler
event/response, which is necessary for the INotifyPropertyChanged
interface. From what I understand, this is how bindings between XAML elements and the ViewModel are kept in sync.
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
try
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
catch (Exception e)
{
// ...
}
}
When I run the code, whenever the RaisePropertyChanged
function is called for the NestedUserControl
, the PropertyChanged
event is always null. This is only a problem for the nested usercontrol, and not the outer one. Shouldn't this event be automatically set via the binding mechanism?
I've been struggling with this for several days now to no avail. Any help would be much appreciated. Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
绑定到
DependencyObject
无需使用INotifyPropertyChanged
接口即可进行操作。事实上,如果您在NestedUserControl
的CustomNestedValue
属性的 getter 或 setter 中设置断点,您会发现在 XAML 中绑定时它永远不会命中。本质上,INotifyPropertyChanged
是一种实现绑定的方法,无需从DependencyObject
下降。当
MyViewModel.CustomValue
绑定到NestedUserControl
时,绑定代码调用(以伪代码形式):INotifyPropertyChanged.PropertyChanged
事件永远不会注册并将保持为空。然而,这并不一定能解释为什么该值没有返回到 ViewModel。无论如何,您可以删除一些移动部分并使用
这就是我的大部分 DependencyProperties 的编写方式,并且它们确实支持
TwoWay
绑定。Binding to a
DependencyObject
operates without using theINotifyPropertyChanged
interface. In fact, if you set a breakpoint in the getter or setter of theCustomNestedValue
property of theNestedUserControl
, you'll find it will never hit when binding in XAML. In essence, theINotifyPropertyChanged
is a way of achieving binding without descending fromDependencyObject
.When the
MyViewModel.CustomValue
is bound to theNestedUserControl
, the binding code calls (in pseudo code):The
INotifyPropertyChanged.PropertyChanged
event is never registered and will remain null. However, this doesn't necessarily answer why the value isn't going back to the ViewModel.Regardless, you could remove a few moving pieces and go with
That's how most of my DependencyProperties are written and they do support
TwoWay
binding.