在 WPF 双向绑定中,如何检查触发绑定更改的是 UI 元素还是 ViewModel?
In WPF two-way binding, how can you check if it was a UI element or ViewModel that triggered the binding change?
我不确定要搜索什么关键字...迷失在 Google 的海洋中。
我在我的 ViewModel 中的可视元素(滑块)和数值之间指定了双向数据绑定。我想区分值更改是用户启动的还是基于 ViewModel 的,以便我可以有选择地触发应用程序中其他地方的事件。我如何在 XAML 文件的代码隐藏中执行此操作?
2015-02-26 更新:在回答 Amit 的问题时,我需要此功能的原因是我实际上为同一 ViewModel 源的 2 路数据绑定设置了多个视觉元素,因此不区分线索到回调中的无限循环(堆栈溢出)到依赖代码本身具有更新相同值的能力。
旁白 - 第一次在 SO 上适当使用 "stack overflow" 不应该有声望点吗?
我想简短的回答是:不是真的。
当您从 XAML 元素绑定到 ViewModel 属性 时,最终 WPF 绑定系统将调用 ViewModel 中的 属性 setter。一旦进入 setter 方法,您就不知道如何到达那里。您可以检查堆栈以查看您来自哪里,但这将是非常脆弱的代码,而且可能也很慢。
如果 属性 仅由 XAML 绑定或 ViewModel 设置,那么您可以在 ViewModel 中设置某种布尔标志,如下所示:
bool _isBeingSetByVM;
public int Number
{
get { return _number; }
set
{
if (_isBeingSetByVM)
{
// ViewModel has set the property
// Do whatever you need to do...
_isBeingSetByVM = false;
}
if (_number != value)
{
_number = value;
OnPropertyChanged("Number"); // generate PropertyChanged event
}
}
}
int _number;
void SomeMethodInVM()
{
_isBeingSetByVM = true;
Number = 42;
}
但同样,这是非常脆弱的代码,难以维护。正如@Amit 在他的评论中所说,更好的问题可能是为什么 你需要这样做。
最好不要有两种不同的行为。您需要以任何一种方式触发相同的通知并重新计算相同的依赖属性。但是我 运行 遇到过这样的情况,比如说,有时我想触发动画,有时我不想,所以不同的行为 可能 是必要的。
如果您确实需要两种不同的行为,我只会创建两个不同的属性(或一个 属性 和一个方法)。将一个 属性 绑定到 UI,并在您以编程方式设置值时使用另一个。给每一个它需要的副作用。
这不仅使事情变得简单,还意味着您可以为两组行为编写单元测试。
我不确定要搜索什么关键字...迷失在 Google 的海洋中。
我在我的 ViewModel 中的可视元素(滑块)和数值之间指定了双向数据绑定。我想区分值更改是用户启动的还是基于 ViewModel 的,以便我可以有选择地触发应用程序中其他地方的事件。我如何在 XAML 文件的代码隐藏中执行此操作?
2015-02-26 更新:在回答 Amit 的问题时,我需要此功能的原因是我实际上为同一 ViewModel 源的 2 路数据绑定设置了多个视觉元素,因此不区分线索到回调中的无限循环(堆栈溢出)到依赖代码本身具有更新相同值的能力。
旁白 - 第一次在 SO 上适当使用 "stack overflow" 不应该有声望点吗?
我想简短的回答是:不是真的。
当您从 XAML 元素绑定到 ViewModel 属性 时,最终 WPF 绑定系统将调用 ViewModel 中的 属性 setter。一旦进入 setter 方法,您就不知道如何到达那里。您可以检查堆栈以查看您来自哪里,但这将是非常脆弱的代码,而且可能也很慢。
如果 属性 仅由 XAML 绑定或 ViewModel 设置,那么您可以在 ViewModel 中设置某种布尔标志,如下所示:
bool _isBeingSetByVM;
public int Number
{
get { return _number; }
set
{
if (_isBeingSetByVM)
{
// ViewModel has set the property
// Do whatever you need to do...
_isBeingSetByVM = false;
}
if (_number != value)
{
_number = value;
OnPropertyChanged("Number"); // generate PropertyChanged event
}
}
}
int _number;
void SomeMethodInVM()
{
_isBeingSetByVM = true;
Number = 42;
}
但同样,这是非常脆弱的代码,难以维护。正如@Amit 在他的评论中所说,更好的问题可能是为什么 你需要这样做。
最好不要有两种不同的行为。您需要以任何一种方式触发相同的通知并重新计算相同的依赖属性。但是我 运行 遇到过这样的情况,比如说,有时我想触发动画,有时我不想,所以不同的行为 可能 是必要的。
如果您确实需要两种不同的行为,我只会创建两个不同的属性(或一个 属性 和一个方法)。将一个 属性 绑定到 UI,并在您以编程方式设置值时使用另一个。给每一个它需要的副作用。
这不仅使事情变得简单,还意味着您可以为两组行为编写单元测试。