I'm trying to add a listener that adds the price of a stock to a ListView every time it receives a price update from the WebSocket. My code is as follows:
private void Ws_OnMessage(object sender, MessageEventArgs e)
{
dynamic data = JsonConvert.DeserializeObject<dynamic>(e.Data);
double price = data["data"][0]["p"];
string stock = data["data"][0]["s"];
Console.WriteLine(stock " " price.ToString());
string[] arr = {stock, price.ToString()};
ListViewItem itm = new ListViewItem(arr);
portfolioList.Items.Add(itm);
}
When I run this, however, the price is successfully received, but the list is not updated, and instead, the console throws a System.InvalidOperationException.
CodePudding user response:
It's a wilde guess/assume, but... This is, what I think, is happening:
If you get an InvalidOperationException cross-thread operation not valid
means that your handler (Ws_OnMessage) is currently executing on a non UI-thread. A ThreadPool thread for instance. The properties of those controls are checking if the setter is called on the right thread, you're not allowed to update controls from a non UI-thread.
This is how to solve it, but it depends on which project type you've used. WinForms/WPF. The code below will do a "cross-threading-call" and executes the code on the UI thread.
For WPF you can use the Dispatcher to execute code on the UI-Thread;
private void Ws_OnMessage(object sender, MessageEventArgs e)
{
Dispatcher.Invoke(() =>
{
dynamic data = JsonConvert.DeserializeObject<dynamic>(e.Data);
double price = data["data"][0]["p"];
string stock = data["data"][0]["s"];
Console.WriteLine(stock " " price.ToString());
string[] arr = { stock, price.ToString() };
ListViewItem itm = new ListViewItem(arr);
portfolioList.Items.Add(itm);
});
}
For WinForms you do something similar:
private void Ws_OnMessage(object sender, MessageEventArgs e)
{
Invoke(new Action(() =>
{
dynamic data = JsonConvert.DeserializeObject<dynamic>(e.Data);
double price = data["data"][0]["p"];
string stock = data["data"][0]["s"];
Console.WriteLine(stock " " price.ToString());
string[] arr = { stock, price.ToString() };
ListViewItem itm = new ListViewItem(arr);
portfolioList.Items.Add(itm);
}));
}