Home > Net >  Add item to ListView from inside websocket OnMessage listener - C# WindowsFormsApp
Add item to ListView from inside websocket OnMessage listener - C# WindowsFormsApp

Time:07-09

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);
    }));
}
  • Related