使用事件驱动的TCP客户端和NotifyPropertyChanged一起会导致异常。

3
我正在编写一个使用C#语言的控制台应用程序,通过TCP连接到服务器并定期接收数据。我使用了我在这里找到的代码,这是一个易于使用的异步客户端。使用此代码,我的程序启动后建立连接并等待事件:
static void Main(string[] args)
        {
            agents = new ObservableCollection<AgentState>();
            EventDrivenTCPClient client = new EventDrivenTCPClient(IPAddress.Parse("192.168.0.1"), 5000);
            client.DataReceived += new EventDrivenTCPClient.delDataReceived(client_DataReceived);

               client.Connect();

                do
                {
                    while (!Console.KeyAvailable)
                    {
                        Thread.Sleep(50);
                    }

                } while (Console.ReadKey(true).Key != ConsoleKey.Q);

client.Disconnect();

       }

这将启动应用程序,连接到端口5000上的192.168.0.1,然后开始监听响应。当收到响应时,我会使用结果更新一个名为“clients”的ObservableCollection(由对象“ClientState”组成):

 static void client_DataReceived(EventDrivenTCPClient sender, object data)
    {
               string received = data as string;

        string parameters=received.Split(',');

        ClientState thisclient = clients.FirstOrDefault(a => a.clientName == parameters[0]);

        var index = clients.IndexOf(thisclient);
        if (index < 0)
        {

            ClientState newclient = new ClientState();
            newclient.clientName = clientname;
            newclient.currentState = state;
            newclient.currentCampaign = campaign;
            clients.Add(newclient);
        }
        else
        {
            clients[index].currentState = state;
            clients[index].currentCampaign = campaign;
        }

    }

令我惊奇的是,这一切都很好地运作:代码很好地执行了,收集统计数据并添加到和更新ObservableCollection。然而,问题出现在我尝试连接到PropertyChanged时... 首先,我添加了


   clients.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(agents_CollectionChanged);

在Main()方法中,我添加了以下内容:

    static void clients_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {

                 foreach (INotifyPropertyChanged item in e.NewItems)
                     item.PropertyChanged += new PropertyChangedEventHandler(newagent_PropertyChanged); 
    }

我希望这个调用newagent_PropertyChanged方法(目前只是将其输出到控制台)以便在ObservableCollection中发生任何更改时都能被调用,但出现了一个问题,当触发PropertyChanged事件时,我会在TCP代码中的“cbDataRecievedCallbackComplete”方法中得到一个异常:
无法将类型为'ClientState'的对象强制转换为类型'System.ComponentModel.INotifyPropertyChanged'。
因此,某种方式尝试引发PropertyChanged正在导致“cbDataRecievedCallbackComplete”代码被触发;似乎事件“交叉路径”。如果我“捕获”错误,代码就会停止运行,不再处理任何传入数据。
我没有足够的经验知道这是否是我引入的问题还是源代码的问题。我敢打赌是前者:有人能看出问题所在吗?
更新:根据下面的答案,我已经更改了类定义,如下所示:
  public class ClientState : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        public string agentName { get; set; }
        public string currentCampaign { get; set; }

        public string _currentState;
        public string currentState
        {
            get { return _currentState; }
            set
            {
                if (value != _currentState)
                {
                    _currentState = value;
                    OnPropertyChanged("CurrentState");

                }
            }
        }
    }

我预期任何“currentState”的更改都会触发事件。然而,我在同一位置得到一个错误,但是现在错误是:

对象引用未设置为对象的实例。

位于cbDataRecievedCallbackComplete的r.DataReceived.EndInvoke(result)行。


1
那么... 这里最明显的问题是你的ClientState类是否实现了该接口? - Malcolm O'Hare
希望如此 :) 我已经在上面添加了类定义。 - KenD
搞定了!我移除了“CollectionChanged”处理程序和事件,现在每当CurrentState更改时,我都能愉快地收到通知。我不确定是什么解决了问题,但感谢大家指引我正确的方向! - KenD
2个回答

2

这个异常将由以下代码引起:

foreach (INotifyPropertyChanged item in e.NewItems)

您正在将e.NewItems中的每个对象隐式转换为INotifyPropertyChanged。由于e.NewItems包含ClientState的实例,我猜测ClientState没有实现INotifyPropertyChanged


它没有,所以我已经看到了上面的内容。不幸的是,它仍然抛出那个错误 :( - KenD

2
如果你的ClientState类定义不像这样:
public class ClientState : INotifyPropertyChanged

如果您无法将其转换为类型INotifyPropertyChanged,则无法将其转换。您没有获得编译时异常,因为e.NewItems集合是对象类型,因此它会让您尝试将其转换为任何内容。


已修复,请参见上文!感谢您的帮助。 - KenD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接