跨线程操作无效:控制从创建它的线程以外的线程访问 [英] Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on

查看:19
本文介绍了跨线程操作无效:控制从创建它的线程以外的线程访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a scenario. (Windows Forms, C#, .NET)

  1. 有一个主窗体承载一些用户控件.
  2. 用户控件执行一些繁重的数据操作,因此如果我直接调用 UserControl_Load 方法,UI 在加载方法执行期间将变得无响应.
  3. 为了克服这个问题,我在不同的线程上加载数据(尝试尽可能少地更改现有代码)
  4. 我使用了一个后台工作线程,它将加载数据,完成后将通知应用程序它已完成其工作.
  5. 现在出现了一个真正的问题.所有 UI(主窗体及其子用户控件)都是在主主线程上创建的.在 usercontrol 的 LOAD 方法中,我根据 userControl 上某些控件(如文本框)的值获取数据.
  1. There is a main form which hosts some user control.
  2. The user control does some heavy data operation, such that if I directly call the UserControl_Load method the UI become nonresponsive for the duration for load method execution.
  3. To overcome this I load data on different thread (trying to change existing code as little as I can)
  4. I used a background worker thread which will be loading the data and when done will notify the application that it has done its work.
  5. Now came a real problem. All the UI (main form and its child usercontrols) was created on the primary main thread. In the LOAD method of the usercontrol I'm fetching data based on the values of some control (like textbox) on 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.
    }
}

它给出的异常是

跨线程操作无效:控制从创建它的线程以外的线程访问.

Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on.

为了更多地了解这个,我做了一些谷歌搜索,并提出了一个建议,比如使用以下代码

To know more about this I did some googling and a suggestion came up like using the following code

代码 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
    }
}

BUT BUT BUT...看来我又回到了原点.再次申请变得无反应.这似乎是由于第 1 行 if 条件的执行.加载任务再次由父线程完成,而不是我生成的第三个.

BUT BUT BUT... it seems I'm back to square one. The Application again become nonresponsive. It seems to be due to the execution of line #1 if condition. The loading task is again done by the parent thread and not the third that I spawned.

我不知道我认为这是对还是错.我是线程的新手.

I don't know whether I perceived this right or wrong. I'm new to threading.

我该如何解决这个问题,以及执行 Line#1 if block 的效果是什么?

How do I resolve this and also what is the effect of execution of Line#1 if block?

情况是这样的:我想根据控件的值将数据加载到全局变量中.我不想从子线程更改控件的值.我不会从子线程中做到这一点.

The situation is this: I want to load data into a global variable based on the value of a control. I don't want to change the value of a control from the child thread. I'm not going to do it ever from a child thread.

所以只访问值,以便从数据库中获取相应的数据.

So only accessing the value so that the corresponding data can be fetched from the database.

推荐答案

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

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

I guess I have not presented the question properly.

情况是这样的:我想根据控件的值将数据加载到全局变量中.我不想从子线程更改控件的值.我永远不会从子线程中做到这一点.

Situation is this: I want to load data into a global variable based on the value of a control. I don't want to change the value of a control from the child thread. I'm not going to do it ever from a child thread.

所以只访问值,以便从数据库中获取相应的数据.

So only accessing the value so that corresponding data can be fetched from the database.

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

The solution you want then should look like:

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

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

Do your serious processing in the separate thread before you attempt to switch back to the control's thread. For example:

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;
        }
    }
}

这篇关于跨线程操作无效:控制从创建它的线程以外的线程访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆