简体   繁体   English

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

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

I want to add more functionality to a project I have that makes use a number of classes packaged in the NET Framework. 我想为我拥有的项目添加更多功能,该功能使用了NET Framework中打包的许多类。 These same classes provide a number of properties which can be quite useful adapting the functionality of my project, however one thing that these classes lack is Events. 这些相同的类提供了许多属性,这些属性对于调整项目的功能非常有用,但是这些类缺少的一件事是事件。

If each property had a appropriate event that would fire whenever the value of such property changed, I could then assign a event handler that would act based on those properties value. 如果每个属性都有一个适当的事件,只要该属性的值更改,该事件就会触发,那么我可以分配一个事件处理程序,该事件处理程序将基于这些属性值进行操作。

I made a sample case bellow to illustrate my goal in the most simpler way I could think off. 我做了一个示例案例,用我能想到的最简单的方法来说明我的目标。

Sample case: 样品盒:

The System.Net.Sockets.Socket class ( Socket on MSDN Docs ) has a property named Connected that basically returns true if the socket is connected to a specified end point otherwise returns false. System.Net.Sockets.Socket类( MSDN Docs上的Socket )具有名为Connected的属性,如果套接字连接到指定的端点,则该属性基本上返回true,否则返回false。

What I would like to accomplish is simple. 我想完成的事情很简单。 I would like to keep this property under "watch" and when the value of it changes, fire a event. 我想将此属性保留在“监视”下,并在其值更改时触发一个事件。

Doing that to one of my own classes it would be simple although a bit tiresome using the INotifyPropertyChanged interface , simply because always that my code changed the value of the property I would have to fire the event manually. 对我自己的一个类执行此操作将很简单,尽管使用INotifyPropertyChanged接口有点 ,只是因为我的代码总是会更改属性的值,所以我必须手动触发该事件。 Unfortunately, to best of my knowledge, not even this kind of procedure can be applied to the existing Socket class distributed within NET Framework. 不幸的是,就我所知,这种方法甚至都不能应用于NET Framework中分布的现有Socket类。

Well, this question is becoming quite extensive, sorry, but I hope it gave an insight to my goal. 好吧,这个问题正在变得相当广泛,对不起,但我希望它能为我的目标提供一个见识。

Now simply putting it, I want to watch the Connected property of the Socket class and when the value of it changes, fire an event. 现在简单地说,我想观察Socket类的Connected属性,并在其值更改时触发一个事件。 And if it would be possible to also use such approach to watch variables as well properties, it would be awesome, not just for me, but for everyone who stumbles across this question on SO. 而且如果也可以使用这种方法来监视变量以及属性,那将是很棒的,不仅对我来说,而且对于那些偶然遇到SO问题的人来说都是如此。

A simple and lightweight approach is preferred of course, but most of all, I want to understand how it can be done, so in the future I can apply it in mass scale to other classes. 当然,首选简单轻量级的方法,但最重要的是,我想了解它是如何完成的,因此将来我可以将其大规模应用于其他课程。

I realize I'm asking a lot. 我知道我要问很多。 Many thanks. 非常感谢。

Any questions just ask. 任何问题都可以问。

I implemented a basic class that should get you started. 我实现了一个基础班,应该让您入门。 I'm sure a fully functional, production-ready, thread-safe class would require a bit more work, plus you need to implement your own strategy for when to poll for value changes. 我确信,一个功能齐全,可用于生产的,线程安全的类将需要更多的工作,此外,您还需要实现自己的策略以决定何时轮询价值变化。

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();
    }
}

And the event handling: 和事件处理:

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);

Usage looks something like this: 用法看起来像这样:

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);
    }
}

Notice the constructor takes a simple lambda expression that can evaluate the value you're wanting to observe. 请注意,构造函数采用了一个简单的lambda表达式,该表达式可以评估您要观察的值。

Also note that MainThread.Invoke is just a pseudocode to show it polling for a change on every main thread loop. 还要注意MainThread.Invoke只是一个伪代码,以显示它轮询每个主线程循环上的更改。 I'm sure there are nicer strategies (background thread with a timer interval) for example that could be implemented in a nice, reusable way. 我肯定有更好的策略(例如带有计时器间隔的后台线程)可以用一种不错的,可重用的方式来实现。 Still more work to be done in terms of deregistering the observer. 在注销观察者方面,还有更多工作要做。 Could probably make some nice factory methods or lambda delegates so you don't need to keep the TargettedObserver instance floating around and reduce the amount of wiring/manual code. 可能可以使用一些不错的工厂方法或lambda委托,因此您无需使TargettedObserver实例保持浮动并减少接线/手动代码的数量。 But at least this should be a start. 但这至少应该是一个开始。

What your looking for is an implementation of the Observer Pattern . 您需要的是观察者模式的实现。 Something like this Observable<T> implementation might work. 类似Observable<T>实现可能会起作用。

See also the IObserver<T> Interface in .NET 4: 另请参见.NET 4中的IObserver<T>接口

The IObserver<T> and IObservable<T> interfaces provide a generalized mechanism for push-based notification. IObserver<T>IObservable<T>接口提供了基于推送的通知的通用机制。 The IObservable<T> interface represents the class that sends notifications (the provider); IObservable<T>接口表示发送通知的类(提供者); the IObserver<T> interface represents the class that receives them (the observer). IObserver<T>接口表示接收它们的类(观察者)。 T represents the class that provides the notification information. T表示提供通知信息的类。

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

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