如何在 C# 中调用多个控件

Posted

技术标签:

【中文标题】如何在 C# 中调用多个控件【英文标题】:How to Invoke multiple controls in C# 【发布时间】:2017-09-05 21:03:54 【问题描述】:

我有一个 C# 程序似乎在随机时间卡住了,在随机一段时间后它自行恢复了!当它卡住时,我可以看到内存增长,当它恢复时,内存使用量就下降到正常水平。 CPU 使用率一直正常,没有文件被写入或读取(按设计)。

程序调用外部(第 3 方)DLL 函数与硬件通信,并从运行在不同线程上的 DLL 回调更新 UI。我检查了代码,除了以下代码(已编辑)之外没有发现任何可疑之处:

private void Func(StructType para) 
    if (labelA.InvokeRequired) 
        labelA.BeginInvoke(new MethodInvoker(() => Func(para)));
        return;
    
    if (labelB.InvokeRequired) 
        labelB.BeginInvoke(new MethodInvoker(() => Func(para)));
        return;
    
    labelA.Text = para.A;
    labelB.Text = para.B;

我想知道这是否是从另一个线程更新 UI 元素的正确方法?如果没有,如何修改?

事实上,我调用了 6 个标签和另一种形式(可选)。大多数时候它似乎工作正常,但偶尔会卡住。由于显而易见的原因,我无法在此处发布所有代码,而只是试图从我最怀疑的地方进行故障排除。

提前感谢您的任何建议!

【问题讨论】:

可能是死锁,UI 线程正在执行其他操作(使用 Debug > Windows > Threads 进行诊断)。或者你调用 BeginInvoke() 过于频繁,所以 UI 线程除了处理调用之外不能做任何其他事情,每秒 50 次对于人眼来说已经足够了。 @HansPassant 是的,还有其他函数调用 Invoke 到其他控件。第 3 方 SDK 的示例代码编写相同,但每个函数只有一个 Invoke。我修改了代码,发现我需要同时更新多个标签,这就是我放置多个调用的原因。您能建议一些正确的方法吗? 另一个问题是,如果它导致死锁,为什么它会在某个时候无缘无故地恢复自己?我的应用程序中的回调应该是一个函数每秒调用 30 次,每秒调用另外 30 次,每秒调用一次不同的调用。第一个更新 6 个标签和另一个全屏表单(用于在屏幕上显示图像),第二个更新一个图片框,最后一个更新一个富文本框。当它卡住时,它会等待不同的时间并开始“刷新缓冲区”,并且在刷新缓冲区之前的不同时间会再次卡住,然后循环:( 【参考方案1】:

您不需要单独检查每个控件以确定是否需要调用它 - 只有一个 UI 线程,因此,该检查仅有用一次。请记住——修改任何 UI 组件几乎肯定会级联成一大堆对其他 UI 组件的其他读/写操作;因此,您必须假设如果您正在触摸 任何 UI 对象,则必须假设您正在触摸 所有 UI 组件。

考虑到这一点,我建议您执行一次调用检查,并建议对两个标签的父控件执行检查和调用。

假设 this 指的是这两个标签的父类,我将修改您的代码如下:

private void Func(StructType para) 
    if (this.InvokeRequired) 

        // Elide the explicit delegate declaration; it's not necessary.
        this.BeginInvoke( Func(para) );

        // Elide the return statement - multiple returns are messy, and in this case, easily removed.
    
    else 
       labelA.Text = para.A;
       labelB.Text = para.B;
   

请注意,如果对象被释放,InvokeRequired 返回 false,即使调用线程不是 UI 线程。

【讨论】:

谢谢。它肯定不会被处理掉。我没有尝试在父级(即表单)上调用,但是如果多个回调函数尝试同时调用表单会导致问题吗?另外,谁能解释为什么投反对票?谢谢!

以上是关于如何在 C# 中调用多个控件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 c# 中调用按钮控件宏

c#中如何跨线程调用windows控件

c#中如何从一个控件调用另一个控件?

C#中多个不同控件之间如何设置Tab顺序?

C#中如何在一个窗体中调用另一个窗体控件中的数据?

如何在C#中删除一个控件