转换事件的发送者以在触发事件的字典中查找值

Casting the sender of an event to find the value in a Dictionary that fired the event

在我的 class 中,我有一个私有 C# 字典,其中键是一个字符串,值是一个具有 PropertyChanged 事件的对象。定义如下:

private readonly Dictionary<string, IAlsVariable> m_operatorAudibleSevServerVariables = new Dictionary<string, IAlsVariable>();

在我的构造函数中,我有以下用于填充 Dictionary:

的 foreach
        foreach (var clusterManager in clusterManagers)
        {
            var clusterName = clusterManager.Name;
            string opcDataSourceServer = "server/" + clusterName + ":[2:http://www.alstom.com/Transport/Iconis/S2K/Data]<Organizes>2:S2KServer<Organizes>2:S2KTerritoryMngt<Organizes>2:TASSObject<HasComponent>2:OperatorAudibleSev";
            var opcVariable = m_alsApplication.Database.GetVariable(opcDataSourceServer, null);
            opcVariable.PropertyChanged += OpcVariable_PropertyChanged;
            m_operatorAudibleSevServerVariables.Add(clusterManager.Name, opcVariable);                
        }

如您所见,在我将每个变量(值)的实例添加到字典之前,我还订阅了每个变量的 PropertyChanged 事件。

现在,只要变量的一个实例触发 PropertyChanged 事件,我就会执行(一个)事件处理程序。问题是我不知道字典中的哪个变量触发了 PropertyChanged 事件。

我有一个名为 UpdateAlarmSound 的方法,每当此事件触发时我都需要调用它。我需要传递给此方法的第一个参数是字典中相关变量的键。

我的第一个猜测是转换变量,然后使用该值来搜索键。但我不知道这是否是执行此操作的可靠方法。下面的代码是我所拥有的。它似乎有效,但我怀疑是否还有另一种更好的方法。或者也许我的方法有效,但错误。也许我应该使用 .Equals 而不是 ==

private void OpcVariable_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    var opcVariable = sender as IAlsVariable;
    var key = m_operatorAudibleSevServerVariables.FirstOrDefault(x => x.Value == opcVariable).Key;
    UpdateAlarmSound(key, Convert.ToInt32(opcVariableVtqValue));            
}

它确实可以正常工作。一项改进可能是将 PropertyChanged 事件信息包装在新的自定义 event 和您自己的新 EventArgs 中,并具有 NameopcVariable 实例部分那个事件。这样您就可以避免任何可能导致运行时错误的转换。

这里是 EventArgs 的例子:

public class YourEventArgs : EventArgs
{
    public string Name {get;set;}

    public int OpcVariableVtqValue  {get;set;}

    // If you still need it.
    public string PropertyName {get;set;}
}

以下是在 IAlsVariable 中完成的更改:

public interface IAlsVariable
{
    event EventHandler<YourEventArgs> YourEvent;
}

现在更改实现:

public class SomeAlsVariableImpl : IAlsVariable
{
    public string Name {get;}

    public event EventHandler<YourEventArgs> YourEvent;

    //  Call this method any time you need to raise the event.
    private void RaiseYourEvent(int opcVariableVtqValue)
    {
        YourEvent?.Invoke(this, new YourEventArgs 
        {
             Name = Name,
             OpcVariableVtqValue = opcVariableVtqValue,
        }
    }
}  

现在,在您的主 class 中,您需要订阅以下事件:

        foreach (var clusterManager in clusterManagers)
        {
            var clusterName = clusterManager.Name;
            string opcDataSourceServer = "server/" + clusterName + ":[2:http://www.alstom.com/Transport/Iconis/S2K/Data]<Organizes>2:S2KServer<Organizes>2:S2KTerritoryMngt<Organizes>2:TASSObject<HasComponent>2:OperatorAudibleSev";
            var opcVariable = m_alsApplication.Database.GetVariable(opcDataSourceServer, null);
            opcVariable.YourEvent += OpcVariable_YourEvent;
            m_operatorAudibleSevServerVariables.Add(clusterManager.Name, opcVariable);                
        }

然后:

private void OpcVariable_YourEvent(object sender, YourEventArgs e)
{
    UpdateAlarmSound(e.Name, e.OpcVariableVtqValue));            
}

当你的 main class 被处理以避免内存泄漏时,不要忘记取消订阅事件。