Domanda

I have start c# a few time ago, so there is somethings that are totally diferent from java, a few time ago I face a problem about a thread changing the UI (add rows to a DataGridView) and I found that I had to call the method Invoke to make that happen. I did and all works fine, but now I'm facing a new problem. So, I have a frame that will display some labels added dynamically and in Java i would like this:

 Thread t = new Thread() {
        public void run() {
            while (true) {
                // for each label
                for (it = labels.iterator(); it.hasNext();) {
                    JLabel lb = it.next();
                    if (lb.getLocation().x + lb.getWidth() < 0) {
                            if (msgsRemover.contains(lb.getText().toString())) {
                            it.remove();
                            MyPanel.this.remove(lb);
                            msgsRemover.remove(lb.getText().toString());
                        } else {
                            // if there is no message to be removed, this will just continue
                            // going to the end of the queue
                            MyPanel.this.remove(lb);
                            MyPanel.this.add(lb);
                        }
                        MyPanel.this.repaint();
                        MyPanel.this.validate();
                    }
                    lb.setLocation(lb.getLocation().x - 3, 0);
                }
                MyPanel.this.repaint();


                try {
                    SwingUtilities.invokeAndWait(running);
                    sleep(30);
                } catch (InterruptedException ex) {
                    Logger.getLogger(MyPanel.class.getName()).log(Level.SEVERE, null, ex);
                } catch (InvocationTargetException ex) {
                    Logger.getLogger(MyPanel.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    };

But in C# I have a problem when the thread does:

MyPanel.this.remove(lb);
MyPanel.this.add(lb);

So I did:

  if (lb.Location.X + lb.Width < 0) {

     if (msgsRemover.Contains(lb.Text.ToString())) {
           labels.Remove(label);
           this.Invoke(new MethodInvoker(() => { this.Controls.Remove(lb); }));
           msgsRemover.Remove(lb.Text.ToString());
     } else {
            // if there is no message to be removed, this will just continue
            // going to the end of the queue
             this.Invoke(new MethodInvoker(() => { this.Controls.Remove(lb); }));
             this.Invoke(new MethodInvoker(() => { this.Controls.Add(lb); }));                              
              }
       this.Invoke(new MethodInvoker(() => { this.Refresh(); }));

But know I'm getting an error called "Can not call Invoke or BeginInvoke on a control until the window handle has been created." I have searched for solutions but I didn't find out what can I do to solve this. Thank you in advance for your help!

Edit: start the thread is the last thing I do in the constructor... There is the code:

public MyPanel(Color corLabel, Color back, Font text){
        this.color = corLabel;
    this.backg = back;
    this.textFont = text;
    this.Width = 500000;

        texto = new LinkedList<string>();
    msgs = new LinkedList<MensagemParaEcra>();
    labels = new LinkedList<Label>();
    var it = labels.GetEnumerator();
    var it2 = msgsRemover.GetEnumerator();

    this.FlowDirection = FlowDirection.LeftToRight;
    this.BackColor = backg;
    this.Size = new Size(500000, 30);
    this.Refresh();

    startThread();
    }
È stato utile?

Soluzione

You must start the thread after the control has a handle created in order to be able to do Invoke, the easiest way to do that is override the OnHandleCreated method and start your thread there instead.

public MyPanel(Color corLabel, Color back, Font text)
{
    this.color = corLabel;
    this.backg = back;
    this.textFont = text;
    this.Width = 500000;

        texto = new LinkedList<string>();
    msgs = new LinkedList<MensagemParaEcra>();
    labels = new LinkedList<Label>();
    var it = labels.GetEnumerator();
    var it2 = msgsRemover.GetEnumerator();

    this.FlowDirection = FlowDirection.LeftToRight;
    this.BackColor = backg;
    this.Size = new Size(500000, 30);
    this.Refresh();
}

protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);
    startThread();
}

Altri suggerimenti

The error you are receiving indicates that the target Window hasn't fully created yet. Probably the constructor hasn't finished. Try to hook up to one of the default events (Load, Show etc.) of the target window and make the invoke calls after these are handled.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top