0

I am trying to update a Windows form listbox from a different thread in C#.

I have a button that creates a new thread. This thread calls a method in another class that starts an asynchronous function which populates a list data type.

The contents of the list needs to be set as the contents of the list box each time a new item is added to the list.

Updating the list box, in the same thread it was created, is a problem because of the need to update with each new item; using a loop will make the rest of the form controls unresponsive.

I have tried using

this.Invoke((MethodInvoker)(() => OutputBox.Items.Add(engineOutput)));

found How to add item to listBox from other thread?, but I haven't been able to get this to work. I am not sure if I am have it in the wrong place or it is not relevant to my solution. (The line above has been changed to fit the context of the solution and is shown below in the code snippet).

I have added a simplified version of code that shows where I have tried to implement the above solution and how the a visual explanation of the description above.

public partial class FrmPacketSniffer : Form
{
    protected bool stop = false;

    public FrmPacketSniffer()
    {
        InitializeComponent();
    }


    private void btnStart_Click(object sender, EventArgs e)
    {
        ThreadStart startSniff = new ThreadStart(StartSniffing);
        Thread startThread = new Thread(startSniff);
        startThread.Start();


    }

    private void StartSniffing()
    {
        PacketSniffng sniffer = new PacketSniffing;

        sniffer.Connection(this);
    }

}


class PacketSniffing
{
    public static bool pause = false;

    static List<string> headerList = new List<string>();

    public static void Connection(FrmPacketSniffer frmPacketSniffer)
    {   
        //Creates a socket called con...
        Sniffing(con, frmPacketSniffer);
    }
    private void Sniffing(Socket con, FrmPacketSniffer frmPacketSniffer)
    {

        Action<IAsyncResult> collect = null;
        collect = (ar)=>
        {

            headerList.Add("data");

            //this.Invoke((MethodInvoker)(() => frmPacketSniffer.lstPackets.Items.Add(headerList))); 
           //Here I placed the code mentioned above.

          frmPacketSniffer.lstPackets.DataSource = headerList; //List box 'lstPackets' is the target to update.




            con.BeginReceive(packet, 0, 24, SocketFlags.None, new AsyncCallback(collect), null);
        };


    }
}

Can anyone provide any tips on how I can fix this please?

Thanks

10aples
  • 103
  • 7
  • 1
    What do you mean by "I haven't been able to get this to work"? Is it failing silently? Is it throwing an exception? – 15ee8f99-57ff-4f92-890c-b56153 May 06 '19 at 17:30
  • It gives me an error saying Invoke isnt a member of 'this'. – 10aples May 06 '19 at 18:09
  • It isn't. "this" refers to your class, which doesn't have that method. Try `frmPacketSniffer.Invoke...` instead. – LarsTech May 06 '19 at 18:12
  • Please edit your question to add that information to your question. That is important information. You're calling `Invoke` form something that isn't a control. Give your `PacketSniffing` class a private field `Control _control`, and a constructor parameter `PacketSniffing(Control ctl) { _control = ctl; }. `FrmPacketSniffer` must pass `this` to the constructor of `PacketSniffing`. Then `PacketSniffing` will call `_ctl.Invoke(...)`. If `_ctl` is null when you do that, it will throw an exception, so you must, absolutely must, pass that parameter and initialize the field. – 15ee8f99-57ff-4f92-890c-b56153 May 06 '19 at 18:13

1 Answers1

0

You need to pass the instance of your form to your instance of PacketSniffing when you create it, and then use that instance and call Invoke on it.

Nick
  • 4,787
  • 2
  • 18
  • 24