0

我有一个有几个组合框和一个gridview 的winform。

最初,我正在创建带有行和列的网格视图,并且没有填充数据。

在此处输入图像描述

将数据填充到网格是一项长期运行的任务,它将遍历所有行并读取列标题,并根据它对每个单元格应用不同的颜色和数据。

我想要实现的是在表单加载事件中加载上述网格,并在表单加载后开始将数据填充到网格中,以便用户可以看到发生了什么。同样的事情也适用于组合框值的变化,因为我将根据组合值加载数据。

我尝试过的是这样的......

在表单加载中,我正在调用方法

 private void LoadForm()
        {                        
            DataBind(); // this will load the initial grid without cell data            

            this.BeginInvoke((MethodInvoker)this.LongRunningProcess1);

            this.BeginInvoke((MethodInvoker)this.LongRunningProcess2);

         }

但它仍然需要很长时间,而且我没有响应式 UI。

我也尝试过这样的事情,但没有运气......

            ThreadStart ts = LongRunningProcess1;
            Thread t1 = new Thread(ts);
            t1.Start();

同样使用后台工作人员完成长时间运行的操作会导致“跨线程操作”问题。

 private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
                LongRunningProcess1();
                LongRunningProcess2();           
        }

任何帮助使这项工作都非常感谢..

谢谢

更新

我找到了一个非常酷的解决方案从另一个线程更新您的表单,而无需为每种类型的更新创建委托

感谢您的回答!!!

4

4 回答 4

1

为了避免在后台工作的完成事件中出现 CrossThreadException,请像这样包装您的回调方法:

public void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new RunWorkerCompletedEventHandler(WorkerCompleted), new {sender, e});
    }
    else 
    {
        // Business logic goes here
    }
}

通常,您将在 else 块中填充加载到 GridView 中的数据。另一方面,如果您想从长时间运行的后台任务中逐步填充 GridView,您可以使用来自后台工作人员的回调通过类似的技术实现此目的:

public void Worker_DoWork(object sender, DoWorkEventArgs e)
{
   foreach (var someParameter in parameterList) // Long-running loop 
   {
     var data = LoadData(someParameter); // Load data for row X
     this.Invoke(new Action<object>(UpdateRow),new[]{data});  // Update on UI-thread
   }
}


public void UpdateRow(object data)
{
   // Code to populate DataGrid row X with data from argument
}

请注意,如果您想异步进行 UI 更新,则可以调用 BeginInvoke 而不是 Invoke。在这种情况下,这通常不会产生影响。

于 2012-07-13T08:39:57.883 回答
0

使用 BackgroundWorker 和 RunWorkerAsync 的简单示例。希望这可以帮助。

public partial class Form2 : Form
{

    BackgroundWorker worker = new BackgroundWorker();

    public Form2()
    {

        worker.WorkerReportsProgress = true;
        worker.WorkerSupportsCancellation = true;

        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);

        InitializeComponent();
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        int totalSteps = 5;
        for (int i = 1; i <= totalSteps; i++)
        {
            Thread.Sleep(1000);
            worker.ReportProgress(i);
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        resultText.Text = "Worker complete";
        btnDoWork.Enabled = true;
        progressBar1.Visible = false;
    }

    private void btnDoWork_Click(object sender, EventArgs e)
    {
        progressBar1.Visible = true;
        worker.RunWorkerAsync();
    }

}
于 2012-07-13T10:24:40.550 回答
0

后台工作进程是正确的方法,您只需要通过确保修改表单元素的所有调用都使用Control.Invoke方法包装器来消除所有“跨线程操作”异常。

于 2012-07-13T08:38:01.763 回答
0

如果您想使用后台工作程序/多线程,您可以使用委托更新您的表单(它们在 ui 线程上运行)。请参阅此处的示例:如何从 C# 中的另一个线程更新 GUI?

于 2012-07-13T08:46:49.827 回答