0

I have a client/server system on which the clients behave as slaves to the server. One of my forms has a listview which is populated by the processes running on the client. This same form can only be opened once, because on the second time I get an exception: InvalidOperationException Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

The form constructor:

public ProcessesForm(NetworkStream _stream)
{
    InitializeComponent();

    networkStream = _stream;

    //event on which the process list will be processed
    Server.OnProcessListingReceived += Server_OnProcessListingReceived;

    //request client for process list
    GetProcesses();

    this.ActiveControl = textBox1;
}

Event handler:

private void Server_OnProcessListingReceived(object sender,
                                             EventArgs.ProcessesEventArgs e)
{
    //exception is thrown here
    listView1.Invoke(new EventHandler(delegate { listView1.Items.Clear(); }));

    processes = new List<ProcessesEventArgs.Process>(e.Processes);

    foreach (var item in e.Processes)
    {
        ListViewItem lvi = new ListViewItem(item.Id);
        lvi.SubItems.Add(item.Name);
        lvi.SubItems.Add((Convert.ToInt64(item.Memory) / 1024).ToString());

        listView1.Invoke(new EventHandler(delegate { listView1.Items.Add(lvi); }));
    }
}

I am invoking the listview because the received list processing is done on the respective client thread.

As I stated on the beginning of the post everything works as it should on the first time the form is opened.

What I have already tried:

  • Create handle manually
  • Unassign the OnProcessListingReceived event on form close.
  • Other things which didn't work and I really can't recall.

What could be the cause of this problem?

EDIT:

As Hans Passant said the problem may be thread race, but if this was the case shouldn't lock solve the problem? I tried implementing lock, but didn't work:

lock(listView1)
{
    listView1.Invoke(new EventHandler(delegate { listView1.Items.Clear(); }));
}
Bruno Klein
  • 3,217
  • 5
  • 29
  • 39
  • The error message is pretty explicit. The BeginInvoke or Invoke is being called before the form is completely created. You should make sure that any other threads don't try to do anything with the form until after the Loaded (or "during" the Loaded event). e.g. create the threads or start the threads in the Loaded processing (or hook up the events in the Loaded handler) – Peter Ritchie Mar 30 '13 at 21:17
  • Actually this is one of the things I have already tried and didn't work. I tried using the `Load` and `Shown` event to assign the event and request the client data. – Bruno Klein Mar 30 '13 at 21:26
  • Adding on the issue even if I remove the request and event from the constructor and add it to a button event handler(which can only be pressed after the form has been created) I get the same problem on the second form show. – Bruno Klein Mar 30 '13 at 21:29
  • You probably forgot to unsubscribe the event when the form closes. And even if you did, it probably still doesn't work due to the inevitable threading race. More about this problem in [this answer](http://stackoverflow.com/questions/1731384/how-to-stop-backgroundworker-on-forms-closing-event/1732361#1732361) – Hans Passant Mar 31 '13 at 00:41
  • As stated on the original post, I did unsubscribe the event, as for thread race, I will take a look. – Bruno Klein Mar 31 '13 at 01:05
  • So, I read something about thread race and from what I could understand it happens when multiple threads are trying to access the same data (the same `listview` in this case). But how come both threads are trying to access the same `listview` if the `listview` is being accessed from the UI thread (invoke)? – Bruno Klein Mar 31 '13 at 01:11
  • You might be interested in `Control.IsHandleCreated`. http://msdn.microsoft.com/en-us/library/system.windows.forms.control.ishandlecreated.aspx – Jim Mischel Mar 31 '13 at 04:11
  • I have already tried it. – Bruno Klein Mar 31 '13 at 04:16
  • While debugging I noticed that the issue wouldn't happen, which in my experience is always related to timing (because of breakpoints). When I added a `Thread.Sleep(100)` before the line where the exception is thrown, the issue was "solved". – Bruno Klein Mar 31 '13 at 04:28
  • Why don't you try putting the code after `InitializeComponent` (or at least the event attachment) in the `Load` event of the form? – educampver Mar 31 '13 at 04:45
  • Have you read the post? At all. – Bruno Klein Mar 31 '13 at 05:24

0 Answers0