繁体   English   中英

属性或变量更改值时触发事件

[英]Fire event when a property or variable changes value

我想为我拥有的项目添加更多功能,该功能使用了NET Framework中打包的许多类。 这些相同的类提供了许多属性,这些属性对于调整项目的功能非常有用,但是这些类缺少的一件事是事件。

如果每个属性都有一个适当的事件,只要该属性的值更改,该事件就会触发,那么我可以分配一个事件处理程序,该事件处理程序将基于这些属性值进行操作。

我做了一个示例案例,用我能想到的最简单的方法来说明我的目标。

样品盒:

System.Net.Sockets.Socket类( MSDN Docs上的Socket )具有名为Connected的属性,如果套接字连接到指定的端点,则该属性基本上返回true,否则返回false。

我想完成的事情很简单。 我想将此属性保留在“监视”下,并在其值更改时触发一个事件。

对我自己的一个类执行此操作将很简单,尽管使用INotifyPropertyChanged接口有点 ,只是因为我的代码总是会更改属性的值,所以我必须手动触发该事件。 不幸的是,就我所知,这种方法甚至都不能应用于NET Framework中分布的现有Socket类。

好吧,这个问题正在变得相当广泛,对不起,但我希望它能为我的目标提供一个见识。

现在简单地说,我想观察Socket类的Connected属性,并在其值更改时触发一个事件。 而且如果也可以使用这种方法来监视变量以及属性,那将是很棒的,不仅对我来说,而且对于那些偶然遇到SO问题的人来说都是如此。

当然,首选简单轻量级的方法,但最重要的是,我想了解它是如何完成的,因此将来我可以将其大规模应用于其他课程。

我知道我要问很多。 非常感谢。

任何问题都可以问。

我实现了一个基础班,应该让您入门。 我确信,一个功能齐全,可用于生产的,线程安全的类将需要更多的工作,此外,您还需要实现自己的策略以决定何时轮询价值变化。

public class TargettedObserver<T>
{
    private static readonly EqualityComparer<T> EqualityComparer = EqualityComparer<T>.Default;

    private Func<T> ValueTarget;
    private T OldValue;

    public event ObservedValueChangedEventHandler<T> ValueChanged;

    public TargettedObserver(Func<T> valueTarget)
    {
        this.ValueTarget = valueTarget;
        OldValue = ObtainCurrentValue();
    }

    public bool CheckValue()
    {
        T oldValue = OldValue;
        T newValue = ObtainCurrentValue();

        bool hasValueChanged = CompareValues(oldValue, newValue);

        if (hasValueChanged)
        {
            OldValue = newValue;
            NotifyValueChanged(oldValue, newValue);
        }

        return hasValueChanged;
    }

    private void NotifyValueChanged(T oldValue, T newValue)
    {
        var valueChangedEvent = ValueChanged;
        if (valueChangedEvent != null)
            valueChangedEvent(this, new ObservedValueChangedEventArgs<T>(oldValue, newValue));
    }

    private static bool CompareValues(T oldValue, T newValue)
    {
        return !EqualityComparer.Equals(oldValue, newValue);
    }

    private T ObtainCurrentValue()
    {
        return ValueTarget();
    }
}

和事件处理:

public class ObservedValueChangedEventArgs<T> : EventArgs
{
    public T OldValue { get; private set; }
    public T NewValue { get; private set; }

    public ObservedValueChangedEventArgs(T oldValue, T newValue)
    {
        this.OldValue = oldValue;
        this.NewValue = newValue;
    }
}

public delegate void ObservedValueChangedEventHandler<T>(TargettedObserver<T> observer, ObservedValueChangedEventArgs<T> eventArgs);

用法看起来像这样:

public class TestClass
{
    private Socket MySocket;
    private static TargettedObserver<bool> SocketConnectedObserver;

    public void Main()
    {
        MySocket = new Socket();
        SocketConnectedObserver = new TargettedObserver<bool>(() => MySocket.Connected);
        SocketConnectedObserver.ValueChanged += ReportSocketConnectedStateChanged;
        PerformSocketConnection();

        MainThread.Invoke(PollSocketValue);
    }

    private void PollSocketValue()
    {
        SocketConnectedObserver.CheckValue();
        MainThread.Invoke(PollSocketValue);
    }

    private void ReportSocketConnectedStateChanged(TargettedObserver<bool> observer, ObservedValueChangedEventArgs<bool> eventArgs)
    {
        Console.WriteLine("Socket connection state changed!  OldValue: " + eventArgs.OldValue + ", NewValue: " + eventArgs.NewValue);
    }
}

请注意,构造函数采用了一个简单的lambda表达式,该表达式可以评估您要观察的值。

还要注意MainThread.Invoke只是一个伪代码,以显示它轮询每个主线程循环上的更改。 我肯定有更好的策略(例如带有计时器间隔的后台线程)可以用一种不错的,可重用的方式来实现。 在注销观察者方面,还有更多工作要做。 可能可以使用一些不错的工厂方法或lambda委托,因此您无需使TargettedObserver实例保持浮动并减少接线/手动代码的数量。 但这至少应该是一个开始。

您需要的是观察者模式的实现。 类似Observable<T>实现可能会起作用。

另请参见.NET 4中的IObserver<T>接口

IObserver<T>IObservable<T>接口提供了基于推送的通知的通用机制。 IObservable<T>接口表示发送通知的类(提供者); IObserver<T>接口表示接收它们的类(观察者)。 T表示提供通知信息的类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM