我有一个设想。(Windows Forms, c#, .NET)

There is a main form which hosts some user control. 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. To overcome this I load data on different thread (trying to change existing code as little as I can) 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. 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.
    }
}

它给出的例外是

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

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

代码2

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

    if (textbox1.text == "MyName") // Now it won't 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行if条件的执行。加载任务再次由父线程完成,而不是由我生成的第三个线程完成。

我不知道我认为这是对还是错。

我如何解决这个问题,以及执行第1行if块的效果是什么?

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

因此只有访问值,才能从数据库中获取相应的数据。


当前回答

我有这个问题与FileSystemWatcher,并发现下面的代码解决了这个问题:

焊。SynchronizingObject = this

然后,控件使用当前表单对象处理事件,因此将位于同一线程上。

其他回答

遵循最简单的(在我看来)方法来修改来自另一个线程的对象:

using System.Threading.Tasks;
using System.Threading;

namespace TESTE
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Action<string> DelegateTeste_ModifyText = THREAD_MOD;
            Invoke(DelegateTeste_ModifyText, "MODIFY BY THREAD");
        }

        private void THREAD_MOD(string teste)
        {
            textBox1.Text = teste;
        }
    }
}

这不是解决此错误的推荐方法,但您可以快速抑制它,它将完成工作。对于原型或演示,我更喜欢这样。添加

CheckForIllegalCrossThreadCalls = false

在Form1()构造函数中。

根据Prerak 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;
        }
    }
}

我发现需要在与表单相关的所有方法中随意放置的检查和调用代码太冗长且不需要。下面是一个简单的扩展方法,可以让你完全摆脱它:

public static class Extensions
{
    public static void Invoke<TControlType>(this TControlType control, Action<TControlType> del) 
        where TControlType : Control
        {
            if (control.InvokeRequired)
                control.Invoke(new Action(() => del(control)));
            else
                del(control);
    }
}

然后你可以简单地这样做:

textbox1.Invoke(t => t.Text = "A");

没有更多的混乱-简单。

您只需要使用Invoke或BeginInvoke来完成更改UI所需的最小工作量。你的“heavy”方法应该在另一个线程上执行(例如通过BackgroundWorker),然后使用Control. invoke /Control。BeginInvoke来更新UI。这样你的UI线程就可以自由地处理UI事件等。

关于WinForms的例子,请参阅我的线程文章——尽管这篇文章是在BackgroundWorker出现之前写的,恐怕我还没有在这方面更新它。BackgroundWorker只是稍微简化了一下回调。