一尘不染

跨线程操作无效:从创建该线程的线程以外的线程访问控件

c#

我有一个场景。(Windows窗体,C#、. NET)

  1. 有一个主窗体可以承载一些用户控件。
  2. 用户控件执行一些繁重的数据操作,因此,如果我直接调用该UserControl_Load方法,则UI将在装入方法执行期间无响应。
  3. 为了克服这个问题,我将数据加载到不同的线程上(尝试尽我所能更改现有代码)
  4. 我使用了一个后台工作线程来加载数据,完成后将通知应用程序它已经完成了工作。
  5. 现在出现了一个真正的问题。所有UI(主窗体及其子用户控件)均在主主线程上创建。在usercontrol的LOAD方法中,我基于userControl上某些控件(如文本框)的值获取数据。

伪代码如下所示:

代码1

UserContrl1_LoadDataMethod()
{
    if (textbox1.text == "MyName") // This gives exception
    {
        //Load data corresponding to "MyName".
        //Populate a globale variable List<string> which will be binded to grid at some later stage.
    }
}

它给的例外是

跨线程操作无效:从创建该线程的线程以外的线程访问控件。

要了解更多信息,我进行了一些谷歌搜索,并提出了一条建议,例如使用以下代码

代码2

UserContrl1_LoadDataMethod()
{
    if (InvokeRequired) // Line #1
    {
        this.Invoke(new MethodInvoker(UserContrl1_LoadDataMethod));
        return;
    }

    if (textbox1.text == "MyName") // Now it wont give an exception
    {
    //Load data correspondin to "MyName"
        //Populate a globale variable List<string> which will be binded to grid at some later stage
    }
}

但是但是…看来我又回到了正题。该应用程序再次变得无响应。如果有条件,这似乎是由于执行了第1行。加载任务再次由父线程完成,而不是我产生的第三个任务。

我不知道我是对是错。我是线程新手。

我该如何解决这个问题,如果执行第1行的代码阻塞还会产生什么影响?

情况是这样的 :我想根据控件的值将数据加载到全局变量中。我不想从子线程更改控件的值。我永远不会从子线程执行此操作。

因此,仅访问该值,以便可以从数据库中获取相应的数据。


阅读 219

收藏
2020-05-19

共1个答案

一尘不染

根据Prera​​k K的更新评论(已删除):

我想我没有正确提出问题。

情况是这样的:我想根据控件的值将数据加载到全局变量中。我不想从子线程更改控件的值。我永远不会从子线程执行此操作。

因此,仅访问该值,以便可以从数据库中获取相应的数据。

您想要的解决方案应如下所示:

UserContrl1_LOadDataMethod()
{
    string name = "";
    if(textbox1.InvokeRequired)
    {
        textbox1.Invoke(new MethodInvoker(delegate { name = textbox1.text; }));
    }
    if(name == "MyName")
    {
        // do whatever
    }
}

尝试切换回控件的线程 之前, 请在单独的线程中 进行 认真的处理。例如:

UserContrl1_LOadDataMethod()
{
    if(textbox1.text=="MyName") //<<======Now it wont give exception**
    {
        //Load data correspondin to "MyName"
        //Populate a globale variable List<string> which will be
        //bound to grid at some later stage
        if(InvokeRequired)
        {
            // after we've done all the processing, 
            this.Invoke(new MethodInvoker(delegate {
                // load the control with the appropriate data
            }));
            return;
        }
    }
}
2020-05-19