c# windows形成自定义控件跨线程操作

本文关键字:线程 操作 自定义控件 windows | 更新日期: 2023-09-27 18:17:55

我有一个主窗口窗体,在该窗体中我有代表应用程序中不同屏幕的自定义控件。我想访问这个控件的子控件。有些事我还没明白…有时我得到这样的错误:

跨线程操作无效:控制从线程访问的'lblText'而不是创建它的线程。

但有时一切正常。我不完全明白为什么会出错…可能是外部设备(MEI BillAcceptor)的东西,它有一个事件(在Form1类内部),对控件进行更改……所以让我写一个简单的代码…

//user control
public partial class Screen2 : UserControl
{
    public void changeValue(string txt)
    {
        lblText.Text = txt;
    }
}

和方法changeValue从form1调用时,特定的事件上升…

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        BillAcceptor.SomeBillAcceptorEvent += 
            new SomeBillAcceptorEventHandler(changeText);
    }
    private void changeText(object sender, EventArgs args)
    {
        _screen2.changeValue("some text");
    }
}

所以最烦人的事情是,有时一切都是正常的…所以我的问题是"我必须在这里使用Invoke吗?"或者我如何通过对应用程序进行更少的更改来解决这个问题…

c# windows形成自定义控件跨线程操作

在处理程序中。像这样做。

        if (this.InvokeRequired)
        {
            Invoke(new MethodInvoker(() => 
            {
                _screen2.changeValue("some text");
            }));
        }
        else
        {
            _screen2.changeValue("some text");
        }

我猜事件是在主UI线程之外的另一个线程上引发的。

如果有可能从其他线程调用该方法,则需要使用Invoke

您可以检查this.InvokeRequired(),如果为真,则使用invoke,如果为假则进行正常调用。

由于thread unsafe call

你应该只在程序

中进行线程安全的调用

查看此链接

简短的回答是肯定的,您必须使用Invoke。如果您需要详细信息,请参阅此问题及其公认答案。

顺便说一下,异常只在某些时候被抛出的原因归结为时间问题。你现在有一个竞争条件,有时你很幸运,有时你没有。

顺便说一下,这里有一个非常方便的模式。

  1. 将任何设置form值的代码重构为自己的私有void方法。
  2. 在这个新方法中,调用InvokeRequired。如果它返回true,调用Invoke,传递当前方法以便递归返回。如果返回false,则继续进行更改。
  3. 从事件处理程序调用这个新方法。
例如:

private void ChangeScreen2() {
    if (this.InvokeRequired) {
        this.Invoke(new MethodInvoker(ChangeScreen2));
    }
    else {
        _screen2.changeValue("some text");
    }
}
private void changeText(object sender, EventArgs args)
{
    ChangeScreen2();
}

的想法是,你隔离所有的代码修改的形式到这些方法,总是开始检查InvokeRequiredInvoke本身,如果需要的话。此模式适用于。net 1.0以后的版本。要获得更简洁的方法,请参阅对这个问题的公认答案,它适用于。net 3.0和更高版本。