【问题标题】:c# threads and cannot call invokec#线程并且不能调用invoke
【发布时间】:2013-11-19 19:57:00
【问题描述】:

我前段时间开始c#,所以有些东西与java完全不同,前段时间我遇到了一个线程改变UI的问题>(将行添加到DataGridView),我发现我必须调用方法Invoke 来实现这一点。我做到了,一切正常,但现在我面临一个新问题。所以,我有一个框架会显示一些动态添加的标签,在 Java 中我想要这样:

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

但在 C# 中,当线程执行时我遇到了问题:

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

所以我做到了:

  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(); }));

但知道我收到了一个名为 “在创建窗口句柄之前无法在控件上调用 Invoke 或 BeginInvoke 的错误。” 我已经寻找解决方案,但我没有找到我能做些什么来解决这个问题。 提前感谢您的帮助!

编辑:启动线程是我在构造函数中做的最后一件事...有代码:

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();
    }

【问题讨论】:

  • 不要在工作线程上创建控件。你在要求痛苦。如果您必须对涉及 UI 控件的工作线程执行任何操作,请确保它很简单。你在这里所拥有的甚至都不是很接近。

标签: c# multithreading invoke


【解决方案1】:

您必须在控件创建句柄后启动线程才能执行Invoke,最简单的方法是覆盖OnHandleCreated 方法并在那里启动您的线程。

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();
}

【讨论】:

  • 谢谢,我创建了一个公共方法来调用 startThread() 现在它可以工作了,非常感谢!
【解决方案2】:

您收到的错误表明目标Window 尚未完全创建。可能构造函数还没有完成。尝试连接到目标窗口的默认事件之一(Load、Show 等),并在处理完这些事件后进行调用。

【讨论】:

  • 启动线程是我在构造函数中做的最后一件事......我将使用构造函数编辑我的问题
猜你喜欢
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多