C# C windows窗体自定义控件跨线程操作

C# C windows窗体自定义控件跨线程操作,c#,multithreading,user-controls,invokerequired,C#,Multithreading,User Controls,Invokerequired,我有一个主窗口窗体,在该窗体中我有表示应用程序中不同屏幕的自定义控件。我想访问此控件的子控件。有些东西我不明白…有时我会犯这样的错误: Cross-thread operation not valid: Control 'lblText' accessed from a thread other than the thread it was created on. 当特定事件发生时,从form1调用方法changeValue public partial class Form1 : Form

我有一个主窗口窗体,在该窗体中我有表示应用程序中不同屏幕的自定义控件。我想访问此控件的子控件。有些东西我不明白…有时我会犯这样的错误:

Cross-thread operation not valid: Control 'lblText' accessed from a thread other than the thread it was created on. 当特定事件发生时,从form1调用方法changeValue

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吗?或者我如何解决这个问题,对应用程序的更改更少…

这是由于线程不安全调用造成的

您应该只在程序中进行线程安全调用

检查链接。

这是由于线程不安全调用造成的

您应该只在程序中进行线程安全调用


检查处理程序中的链接。

。像这样做

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

我猜事件是在处理程序中主UI线程以外的单独线程上引发的。

。像这样做

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

我猜事件是在主UI线程以外的单独线程上引发的。

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


您可以对此进行检查。InvokeRequired,如果为true,则使用invoke,如果为false,则执行正常调用。

是的,如果可能从其他线程调用该方法,则需要使用invoke


您可以对此进行检查。InvokeRequired,如果为true,则使用invoke,如果为false,则执行正常调用。

简短的回答是“是”,您必须使用invoke。看

顺便说一句,异常只在某些时候抛出的原因可以归结为时间。你现在有一个比赛条件,有时你会幸运,有时你不会

顺便说一句,这是一个非常方便的模式

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

private void ChangeScreen2() {
    if (this.InvokeRequired) {
        this.Invoke(new MethodInvoker(ChangeScreen2));
    }
    else {
        _screen2.changeValue("some text");
    }
}

private void changeText(object sender, EventArgs args)
{
    ChangeScreen2();
}

其思想是将所有修改表单的代码隔离到这些方法中,这些方法总是从检查invokererequired开始,如果需要,总是调用它们自己。此模式适用于.NET1.0以后的版本。对于更简洁的方法,请参阅可用于.NET 3.0及更高版本的已接受答案。

简短的答案是“是”,您必须使用Invoke。看

顺便说一句,异常只在某些时候抛出的原因可以归结为时间。你现在有一个比赛条件,有时你会幸运,有时你不会

顺便说一句,这是一个非常方便的模式

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

private void ChangeScreen2() {
    if (this.InvokeRequired) {
        this.Invoke(new MethodInvoker(ChangeScreen2));
    }
    else {
        _screen2.changeValue("some text");
    }
}

private void changeText(object sender, EventArgs args)
{
    ChangeScreen2();
}

其思想是将所有修改表单的代码隔离到这些方法中,这些方法总是从检查invokererequired开始,如果需要,总是调用它们自己。此模式适用于.NET1.0以后的版本。对于更简洁的方法,请参阅可用于.NET 3.0及更高版本的已接受答案。

已回答,因此我只需添加以下注释:与UI交互的所有内容都必须在主UI线程上。任何其他工作线程都必须使用Method.Invoke,然后才能直接与UI交互。已回答,因此我将添加以下注释:与UI交互的所有内容都必须在主UI线程上。任何其他工作线程都必须使用Method.Invoke,然后才能直接与UI交互。