我正在编写一个使用C#语言的控制台应用程序,通过TCP连接到服务器并定期接收数据。我使用了我在这里找到的代码,这是一个易于使用的异步客户端。使用此代码,我的程序启动后建立连接并等待事件:
令我惊奇的是,这一切都很好地运作:代码很好地执行了,收集统计数据并添加到和更新ObservableCollection。然而,问题出现在我尝试连接到PropertyChanged时... 首先,我添加了。
我希望这个调用newagent_PropertyChanged方法(目前只是将其输出到控制台)以便在ObservableCollection中发生任何更改时都能被调用,但出现了一个问题,当触发PropertyChanged事件时,我会在TCP代码中的“cbDataRecievedCallbackComplete”方法中得到一个异常:
无法将类型为'ClientState'的对象强制转换为类型'System.ComponentModel.INotifyPropertyChanged'。
因此,某种方式尝试引发PropertyChanged正在导致“cbDataRecievedCallbackComplete”代码被触发;似乎事件“交叉路径”。如果我“捕获”错误,代码就会停止运行,不再处理任何传入数据。
我没有足够的经验知道这是否是我引入的问题还是源代码的问题。我敢打赌是前者:有人能看出问题所在吗?
更新:根据下面的答案,我已经更改了类定义,如下所示:
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)行。