无限循环的事件

Infinite loop of events

假设我在 c# (winforms) 中有一个简单的表单,其中包含两个文本框、一个滑块和一个名为 "the_volume" 的对象。只要 "the_volume.value" 发生变化,就会发送一个事件 (OnPropertyChanged)。我怎样才能 CLEANLY 同步四个对象而不导致无限循环?

小例子:滑块变化 --> form::slider_changed --> 设置 the_volume --> form::the_volume_changed --> 设置滑块和文本框值 --> 无限循环...

我的第一直觉是避免在值未更改时发送事件,但是,

1- 我怎么知道 .net 控件是否会做同样的事情? (即如果值相同则不触发)

2- 让我感到困扰的是,这个解决方案会有一个 "useless" setter 调用(设置 -> 更改 -> 设置 -> 停止循环)

我会有一个对象负责路由事件。我们称它为 VolumeChangedEventRouter。它将有自己的 "volume changed" 其他实体可以订阅的事件。

VolumeChangedEventRouter 将订阅(或被订阅)您的每个可能引发 "volume changed" 事件的控件。

然后您的每个控件都将订阅(或将订阅)VolumeChangedEventRouter 的 "volume changed" 事件。

然后 VolumeChangedEventRouter 会知道当前音量,因此它会知道它是否已更改,从而知道是否将事件传递给它的订阅者。

您可能会使用依赖注入将 VolumeChangedEventRouter 传递给每个需要订阅其 "volume changed" 事件的 类。 (您甚至可能想要设计 VolumeChangedEventRouter 以便它实现一个仅包含 "volume changed" 事件的接口,并将其传递给控件以最小化依赖性。)

甚至可能有一个由 VolumeChangedEventRouter 和所有控件实现的通用 IVolumeChanger 接口,因为它们都将引发 "volume changed" 事件。这将大大减少耦合。

我知道这是一个 WinForms 问题,但 WPF 的处理方式应该可以帮助您解决问题。您可以研究 INotifyPropertyChanged 示例以获取更多详细信息,但这是基础知识:

//have a backing variable
private double _volume = 0;

//have a property
public double Volume
{
    get { return _volume; }
    set
    {
        // prevent any event firing if nothing changed
        if( _volume == value )
        {
            return;
        }

        // now we can set
        _volume = value;

        // something really changed, fire some event
        this.NotifyPropertyChanged();
    }
}

现在只有当确实发生变化时,您的所有听众才会收到通知。这种类型的 check then fire 几乎可以应用于您遇到的任何观察者模式问题。正如您在问题中所述,这将防止事件循环。