使用事件驱动的TCP客户端和NotifyPropertyChanged会导致异常(Using event

编程入门 行业动态 更新时间:2024-10-22 05:18:48
使用事件驱动的TCP客户端和NotifyPropertyChanged会导致异常(Using event-driven TCP client and NotifyPropertyChanged together causes exception)

我正在编写一个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); }

我希望在ObservableCollection发生任何变化时调用newagent_PropertyChanged方法(此时只是吐出到控制台)..但是有些原因,一旦触发了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”的任何更改都能触发事件。 但是,我在同一个地方收到错误,但现在错误是:

你调用的对象是空的。

在r.DataReceived.EndInvoke(result)行中。

I'm writing a C# console application that connects to a server via TCP and receives periodic data back. I'm using some code I found here, which is a nice easy to use async client. Using this, my code starts up, makes a connection and then waits for events:

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

This starts up the app, connects to 192.168.0.1 on port 5000 and then starts listening for responses. When they're received, I update an ObservableCollection called "clients" (comprised of object "ClientState") with the results:

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

To my great surprise, this all works fine: the code ticks along nicely, collecting the stats and adding to and updating the ObservableCollection. However, the problem is when I try to hook into the PropertyChanged... firstly, I add

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

to Main(), then I add:

static void clients_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { foreach (INotifyPropertyChanged item in e.NewItems) item.PropertyChanged += new PropertyChangedEventHandler(newagent_PropertyChanged); }

I'd like this to call the newagent_PropertyChanged method (which just spits out to the Console at the moment) when anything changes in the ObservableCollection .. but some reason, as soon as a PropertyChanged event is fired, I get an exception in the "cbDataRecievedCallbackComplete" method in the TCP code:

Unable to cast object of type 'ClientState' to type 'System.ComponentModel.INotifyPropertyChanged'.

... so somehow, the act of trying to raise a PropertyChanged is causing the "cbDataRecievedCallbackComplete" code to fire; it's almost as if the events are "crossing paths". If I "catch" the error the code grinds to a halt and doesn't process any more incoming data.

I don't have enough experience to know if this is a problem that I've introduced, or with the source code. I'll put money on it being the former: can anyone see where there problem lies?

UPDATE: In response to the answers below, I've changed my class definition to look like:

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

... so I'd expect any changes to "currentState" to trigger an event. However, I get an error in the same place, except now the error is:

Object reference not set to an instance of an object.

in the r.DataReceived.EndInvoke(result) line of the cbDataRecievedCallbackComplete.

最满意答案

如果ClientState的类定义看起来不像这样

public class ClientState : INotifyPropertyChanged

那么你不能把它强制转换为INotifyPropertyChanged类型。 您没有获得编译时异常,因为e.NewItems集合的类型为object,因此它会让您尝试将其强制转换为任何内容。

If your class definition for ClientState doesn't look something like this

public class ClientState : INotifyPropertyChanged

then you cannot cast it to the type INotifyPropertyChanged. You aren't getting a compile time exception because the e.NewItems collection is of type object so it will let you try to cast it to anything.

更多推荐

本文发布于:2023-08-05 19:37:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1438020.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:客户端   异常   事件   event   TCP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!