【问题标题】:In WPF two-way binding, how can you check if it was a UI element or ViewModel that triggered the binding change?在 WPF 双向绑定中,如何检查是 UI 元素还是 ViewModel 触发了绑定更改?
【发布时间】:2015-03-18 04:27:12
【问题描述】:

我不确定要搜索什么关键字...迷失在谷歌的海洋中。

我在 ViewModel 中的可视元素(滑块)和数值之间指定了双向数据绑定。我想区分值更改是用户发起的还是基于 ViewModel 的,这样我就可以有选择地在我的应用程序的其他地方触发事件。如何在 XAML 文件的代码隐藏中执行此操作?

2015-02-26 更新:在回答 Amit 的问题时,为什么我需要此功能是因为我实际上为同一个 ViewModel 源的 2 向数据绑定设置了多个可视元素,因此不区分会导致对本身有能力更新相同值的依赖代码的回调中的无限循环(堆栈溢出)。

除此之外 - 第一次适当地使用 SO 上的“堆栈溢出”不应该有声誉点吗?

【问题讨论】:

  • 好吧,我很困惑。您想要响应 XAML 文件代码隐藏中的 ViewModel 属性更改?好像你在这里混合世界。您打算如何在 ViewModel 和代码隐藏之间进行通信?
  • @David Cuccia 为什么你想知道是谁修改了它?
  • 如果 UI 设置了一个值,则源正在更新.. 如果 VM 设置了一个值,则目标正在更新.. 在我看来你正在寻找这个:msdn.microsoft.com/en-us/library/ms746700%28v=vs.110%29.aspx
  • @AmitRaz 我本来可以更清楚的。实际上,我有不止一个可视元素与同一个 ViewModel 源的 2 路数据绑定,所以 not 区分会导致在对相关代码的回调中出现无限循环(堆栈溢出;))。
  • @devhedgehog 谢谢。我会记住这个钩子。

标签: c# wpf xaml mvvm data-binding


【解决方案1】:

我认为简短的回答是:不是。

当您从 XAML 元素绑定到 ViewModel 属性时,最终 WPF 绑定系统将调用 ViewModel 中的属性设置器。一旦进入 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 在他的评论中所说,更好的问题可能是为什么你需要这样做。

【讨论】:

  • 谢谢 - 这基本上是我最终做的。对此并不完全满意,但在我的情况下,这是唯一看起来相当简单的事情。
  • 我记得在 90 年代使用 Visual Basic 3 时这样做过。我们将“isBeingSetByVM”称为“Zelda”变量,但我不记得为什么了。
【解决方案2】:

最好不要有两种不同的行为。无论哪种方式,您都需要触发相同的通知并重新计算相同的依赖属性。但是我遇到过这样的情况,比如说,有时我想触发动画,有时我不想,所以不同的行为可能是必要的。

如果你真的需要两种不同的行为,我只会创建两个不同的属性(或一个属性和一个方法)。将一个属性绑定到 UI,并在以编程方式设置值时使用另一个。给每个人它需要的副作用。

这不仅使事情变得简单,还意味着您可以为这两组行为编写单元测试。

【讨论】:

  • 谢谢。我怀疑这可能是正确的方法,但我无法干净地重构我们的代码以隔离副作用。最终使用了适合我需要的 Steven Rands 方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-29
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2012-03-05
  • 2010-09-24
  • 1970-01-01
相关资源
最近更新 更多