简体   繁体   English

从非ui线程更新控件

[英]updating controls from non-ui thread

Guys I know this question has been asked many times but I still cannot find a single reply that makes sense to me. 伙计我知道这个问题已被多次询问,但我仍然找不到对我有意义的单一回复。

I have a form with over 400 controls on it. 我有一个包含400多个控件的表单。

I have a background thread that polls a bunch of equipment and gathers all kinds of data to be displayed on the form. 我有一个后台线程,可以轮询一堆设备并收集要在表单上显示的各种数据。

I then call one method "UpdateDisplay(string[] data)". 然后我调用一个方法“UpdateDisplay(string [] data)”。 This one routine takes all the information in the string array data[] and fills in all the components on the form. 这个例程获取字符串数组data []中的所有信息,并填写表单上的所有组件。 I have Labels, TextBoxes being filled in. Panels and TableLayouts and other controls being shown and hidden. 我填写了标签,文本框。显示和隐藏了面板和TableLayout以及其他控件。

HUNDREDS of them!! 他们几百!

If I have to test each and every component to see if I have to invoke my program will turn into 5 billion lines of code!!!!! 如果我必须测试每个组件,看看我是否必须调用我的程序将变成50亿行代码!!!!!

Is there some way to simply see if the entire UpdateDisplay method needs to be invoked on the UI thread rather then all 400+ components it touches? 有没有办法简单地看看是否需要在UI线程上调用整个UpdateDisplay方法,而不是它接触到的所有400多个组件?

I put the following code: 我把以下代码:

    if (InvokeRequired)
    {
        BeginInvoke(new MethodInvoker(() => UpdateDisplay(data)));
    }

as the first statement in the display method and I no longer get the run time exception about calling ui components from a non-ui thread. 作为display方法中的第一个语句,我不再获得有关从非ui线程调用ui组件的运行时异常。

followed by the rest of the update method with hundreds of components being updated with the information in data[] 其次是更新方法的其余部分,数百个组件正在使用data []中的信息进行更新

But now I am getting a bunch of System.InvalidOperationException in System.Forms.dll??? 但是现在我在System.Forms.dll中收到了一堆System.InvalidOperationException ???

If I set the debug exception option to break on all invalidoperationexceptions I see that they are being thrown randomly when updating components within the UpdateDisplay method with the nastygram about updating components from the non-ui thread. 如果我将调试异常选项设置为中断所有invalidoperationexceptions,我会发现当使用关于从非ui线程更新组件的讨厌的内容更新UpdateDisplay方法中的组件时,它们会被随机抛出。

Can someone please help me understand and fix this? 有人可以帮我理解并解决这个问题吗?

I can post the entire UpdateDisplay method to show how rediculous it would be if I had to wrap every component update call with an invokerequired if statement. 我可以发布整个UpdateDisplay方法,以显示如果我必须使用invokerequired if语句包装每个组件更新调用,那将是多么荒谬。 Not exaggerating it would add like three lines of code per control or roughly 1200 lines of additional code!! 不夸张它会增加每个控件三行代码或大约1200行额外代码! That is just crazy! 那太疯狂了!

This is a sample of how I update a ListBox with messages from another thread. 这是我如何使用来自另一个线程的消息更新ListBox的示例。

private void WriteProgressMessage(string message)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new Action(() => this.WriteProgressMessage(message)));
    }
    else
    {
        this.ProgressList.Items.Add(message);
        this.ProgressList.SelectedIndex = this.ProgressList.Items.Count - 1;
        this.ProgressList.SelectedIndex = -1;
    }
}

You did not provide sufficient code, but if your method looks something like this: 您没有提供足够的代码,但如果您的方法看起来像这样:

void UpdateDisplay(string[] data)
{
    if (InvokeRequired)
    {
        BeginInvoke(new MethodInvoker(() => UpdateDisplay(data)));
    }
    Label1.Text = data[0];
    // Update more controls here
}

then you are running UpdateDisplay twice, once on the UI thread due to the BeginInvoke and once on the worker thread when BeginInvoke returns. 然后你运行UpdateDisplay两次,一次在UI线程上由于BeginInvoke而在BeginInvoke返回时在工作线程上运行一次。 The usual pattern is that if you use Invoke or BeginInvoke to invoke yourself, the method then returns immediately and does no further processing: 通常的模式是,如果您使用InvokeBeginInvoke来自行调用,则该方法立即返回并且不进行进一步处理:

void UpdateDisplay(string[] data)
{
    if (InvokeRequired)
    {
        BeginInvoke(new MethodInvoker(() => UpdateDisplay(data)));
        return; // Don't run any code below when BeginInvoke returns
    }
    Label1.Text = data[0];
    // Update more controls here
}

JimmyV also gave an alternate version that also does no further work after the BeginInvoke : JimmyV还提供了一个替代版本,在BeginInvoke之后也没有进一步的工作:

void UpdateDisplay(string[] data)
{
    if (InvokeRequired)
    {
        BeginInvoke(new MethodInvoker(() => UpdateDisplay(data)));
    }
    else // Don't run any code below when BeginInvoke returns
    {
        Label1.Text = data[0];
        // Update more controls here
    }
}

One possibility is that since you are using BeingInvoke , rather than Invoke to update the UI thread there may be an issue of synchronisation. 一种可能性是,由于您使用的是BeingInvokerather than Invoke来更新UI线程,因此可能存在同步问题。 Its hard to tell without seeing a more complete code sample, buy try calling Invoke instead and see if you get less errors 如果没有看到更完整的代码示例很难分辨,请尝试调用Invoke ,看看你是否得到更少的错误

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM