EventToCommand - 在处理选择更改时如何防止递归/重入调用

发布于 2024-11-30 06:49:21 字数 527 浏览 0 评论 0原文

请在此处查看模型代码

我正在创建一个交互式搜索页面,该页面在用户输入条件时获取数据。长话短说,我有几个组合框,它们的 SelectionChanged 事件由 EventToCommand 处理。

EventToCommand 调用我的 ViewModel 上的一个方法,该方法除其他外,还更改多个组合框的选定项目。当然,这会触发 EventToCommand 并且整个过程会再次发生...一次...一次...

所以我的问题是,有没有办法绑定到 EventToCommand 真的OneWayToSource 以便来自源的更新不会触发事件吗?

Please see mockup code here

I am creating an interactive search page that fetches data as the user inputs criteria. To make a long story short I have several combo boxes that have their SelectionChanged event handled by EventToCommand.

EventToCommand calls a method on my ViewModel that, among other things, changes the selected item for several combo boxes. Of course that triggers EventToCommand and the whole process happens again... and again... and again....

So my question is, is there a way to make the binding to EventToCommand truly OneWayToSource so that an update from the source does not trigger the event?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

城歌 2024-12-07 06:49:21

下面的方法 1 显示了一种可能有价值的技术说明,但方法 2 可能最适合大多数应用程序。

方法 1

作为第一种方法,我采用了 jberger 建议的方法。然而,由于我依赖于事件参数中包含的值,并且我希望根据 MVVM 目标和原则保持 View 和 ViewModel 之间的关注点分离,因此我将这个添加的逻辑放置在我的代码隐藏中,以保持依赖关系查看代码。

我使用事件参数的 AddItems 内容的哈希来区分由于另一个 ComboBox 上的属性绑定而导致的“重复”调用与由于用户交互而对事件处理方法的新调用。

    int hashCode = 0;
    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      string addedItemsCatString = "";
      foreach (string item in e.AddedItems) addedItemsCatString += item;
      int newHashCode = addedItemsCatString.GetHashCode();
      if ( newHashCode == hashCode) return;
      hashCode = newHashCode;

      // execute Command code here
    }

对于一次只能选择一个项目的 ComboBox 来说,连接 AddedItems 的内容并不是严格必要的,但它允许在多选控件上使用类似的方法。

方法2

由于我对方法1并不完全满意,所以我一直在思考更好的解决方案。我的见解是,我实际上只想根据用户交互发出一次命令。键盘焦点看起来是一个很好的标志,可以区分用户交互引起的 SelectionChanged 事件和属性绑定引起的 SelectionChanged 事件。

private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
  if (!(sender as FrameworkElement).IsKeyboardFocusWithin) return;

      // execute Command code here

}

因此,上述测试可能是大多数情况下的最佳解决方案,包括由不涉及任何 GUI 选择器的另一种输入模式启动 SelectionChanged 事件的情况,例如键盘快捷键或内部状态更改。程序 - 或任何可能执行命令的地方,如果您使用多个控件来控制设置,则该命令将导致多个 SelectionChanged 事件触发。实例属性 FrameworkElement.IsKeyboardFocused 属性和静态 Keyboard.Focus(frameworkElementInstance) 方法也可能对不同的控件或方案有用。

有关键盘焦点的更多信息,请访问 msdn 此处

Method 1 below shows a perhaps valuable illustration of a technique, but most applications will probably be best served by Method 2.

Method 1

As a first approach, I took the approach suggested by jberger. However, since I am relying upon values contained in the event args, and I want to maintain the separation of concerns between my View and ViewModel as per MVVM goals and principles, I placed this added logic in my code-behind to keep the dependency in the View code.

I used a hash of the AddedItems contents of the event args to distinguish "repeat" calls due to property binding on another ComboBox from new calls to the event handling method due to user interaction.

    int hashCode = 0;
    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
      string addedItemsCatString = "";
      foreach (string item in e.AddedItems) addedItemsCatString += item;
      int newHashCode = addedItemsCatString.GetHashCode();
      if ( newHashCode == hashCode) return;
      hashCode = newHashCode;

      // execute Command code here
    }

Concatenating the contents of AddedItems is not strictly necessary for a ComboBox where only one item can be selected at a time, but it allows for a similar approach on multi-select controls.

Method 2

Since I was not completely satisfied with Method 1, I kept thinking about a better solution. The insight that came to me was that I really was only looking to issue the command once, based upon a user interaction. What looks like a good flag to distinguish a SelectionChanged event due to a user interaction from those due to a property binding is keyboard focus.

private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
  if (!(sender as FrameworkElement).IsKeyboardFocusWithin) return;

      // execute Command code here

}

As such the above test may be the best solution for the bulk of cases, including ones where a SelectionChanged event is initiated by another mode of input not involving any of your GUI selectors, such as a keyboard shortcut or an internal change in state of your program - or any place you might execute a Command which would result in multiple SelectionChanged events firing if you used multiple controls to control a setting. The instance property FrameworkElement.IsKeyboardFocused property and the static Keyboard.Focus(frameworkElementInstance) method may also be useful for different controls or scenarios.

More on Keyboard focus can be found on msdn here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文