2009-08-18 74 views
1

我了解如何使用委托来更新主控制线程上的控件,就像魅力一样。我的问题在于,如果我将大型DataSet(如2000项)添加到绑定DataGridView,则需要5-8秒才能填充网格,并且在此期间整个GUI将被锁定5-8秒。我如何更新DataGridView,使其不锁定用户界面?对DataGridView的无阻塞更新

需要明确的是,这个问题是不是我做了慢速查询到数据库和UI阻止对,我已经有DataSet object[]和添加对象的数组到BindingList<object>DataGrid是势必使:

BindingList<object> dataProvider = new BindingList<object>(); 
DataGridView gridView = new DataGridView(); 
gridView.DataSource = dataProvider; 

// ...stuff happens... 

object[] source = dataSet; //of 2000 items 
foreach (object item in source) { //this foreach blocks 
    dataProvider.Add(item); 
} 

我尝试过各种东西(我知道是行不通的,但想我会看到),如创建一个委托,它做了dataProvider.Add(),但由于它仍然不得不说没有问题发生在控制线程上。

一些好的建议围绕构建BindingList首先,然后设置gridView.DataSource。虽然这可以工作(它立即更新网格),但我看到添加更多数据的唯一方法是创建另一个新的BindingList,执行gridView.DataSource.copyTo()(获取现有数据)并在其上添加新数据,然后设置gridView.DataSource到新的BindingList。这对我不起作用,因为列表中的对象不是静态的,它们每个都将数据异步上传到服务器,并将它们复制到新的BindingList会导致问题。

回答

1

您在GridView链接到DataSource时添加记录。这意味着它会每次更新布局。

你先填充你的DataSource然后设置DataSource属性如何?

gridView.DataSource = null; 
...stuff happens... 

object[] source = dataSet; //of 2000 items 
foreach (object item in source) { //this foreach blocks 
    dataProvider.Add(item); 
} 

gridView.DataSource = dataProvider; 

foreach循环可以去另一个线程,但我不认为你会需要它。

+0

foreach循环应该到另一个线程,但是这仍然是个好主意。 – user142350 2009-08-18 20:45:14

+0

这取决于一点,但添加2000项通常可以接受正常事件。我收集他们已经在记忆中。 – 2009-08-18 20:56:17

+0

我试着把foreach循环放在不同的线程中,但是这并没有帮助,因为每个.Add都必须在控制线程上发生,这意味着整个foreach仍然在控制线程上发生。 Henk是正确的,如果我将所有项目添加到BindingList,然后将gridView.DataSource设置为BindingList,然后立即更新。这里的问题是,如果我想添加更多的项目到gridView我必须创建一个新的BindingList,复制所有现有的项目,并添加更多。这打破了我在当前数据上运行的任何操作(并且感觉像是黑客)。 – Shizam 2009-08-18 21:01:09

0

使用研究BackgroundWorker。我自己对这些事情不太了解,但是在Google上搜索一下,发现这是一个很好的可能性。

3

像尼克说的BackgroundWorker可能是你最好的选择。

这是一个非常简单的例子

public partial class Form1 : Form 
{ 
    BackgroundWorker b = new BackgroundWorker(); 

    public Form1() 
    { 
     InitializeComponent(); 
     b.RunWorkerCompleted += new RunWorkerCompletedEventHandler(b_RunWorkerCompleted); 
     b.DoWork += new DoWorkEventHandler(b_DoWork); 
    } 

    void b_DoWork(object sender, DoWorkEventArgs e) 
    { 
     // build dataset here and assigning it to results 
     e.Result = dataset;    
    } 

    void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     // assign the dataset you built in DoWork in the gridview and update it 
     dataGridView1.DataSource = e.Result; 
     dataGridView1.Update(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     b.RunWorkerAsync(); 
    } 
} 
+0

这是另一个很好的建议,但每次添加更多数据而不是将更多数据添加到现有数据源时,需要更换DataSource。这是一个问题,因为dataSource中的对象正在将数据上传到服务器,所以我不能只做一个BindingList.copyTo(),因为每个对象都不是静态的。 – Shizam 2009-08-18 21:06:33

+0

Shizam,你试过这个吗?只要元素是类(而不是结构),应该没有问题。 – 2009-08-18 21:33:26