在不冻结GUI的情况下向DataGridView添加行

时间:2017-11-16 16:21:37

标签: c# winforms user-interface datagridview

我想要显示一张桌子。表的数据必须预先计算,并且计算量很大。结果表也很长。 我希望提供对部分数据的访问,而另一部分则在后台计算。

我编写后台工作程序进行计算,使用DataGridView进行显示。有时工作人员通过ProgressChangedEvent提交新行。我试图在底部添加这些行。 当我尝试在底部添加新行时,我的问题就出现了。我的用户界面冻结了。

以下是我初始化DataGridView的方法:

private void InitDataGridView() 
{
    BindingList<TableRow> tableRows = new BindingList<TableRow>();
    dataGridView.DataSource = tableRows;
}

以下是我在ProgressChangedEvent

中添加新行的方法
private void UpdateDataGridView (List<Items> newItems)
{
    BindingList<TableRow> dataSource = (BindingList<TableRow>)this.dataGridView.DataSource;
    foreach (var item in newItems)
        dataSource.Add(new TableRow(item));
}

我认为这个问题是因为添加一行会重新开始重绘表格。 但我没有找到AddRange for BindingList或机制来暂停渲染。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

通过向列表中添加新项目,BindingList会引发ListChanged,从而导致更新DataGridView。为了提高DataGridView的效率,您可以选择停止提升ListChanged的{​​{1}}事件。这样,您可以在添加项目之前将其关闭,然后在将一组项目添加到列表后立即将其打开并引发事件。

这是一个支持启用/关闭BindingList事件的实现:

ListChanged

例如,在添加项目时禁用该事件::

public class MyBindingList<T>:BindingList<T>
{
    public bool EnableChangeNotifications { get; set; }
    protected override void OnListChanged(ListChangedEventArgs e)
    {
        if(EnableChangeNotifications)
            base.OnListChanged(e);
    }
}

然后要显示list.EnableChangeNotifications = false; //Add new items to the list using a loop or something else. 中的更改,请启用该事件并将其抬起:

DataGridView

答案 1 :(得分:0)

尝试将AutoSizeColumnsMode属性设置为NoneDisplayedCells,并在每列的AutoSizeMode上设置:

foreach (DataGridViewColumn c in thisGrid.Columns)
{
    c.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
}

尝试在绑定之前和之后以及更新时切换。

此外,您可以尝试在此answer上建议的内容并启用双缓冲:

if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
{
  Type dgvType = dataGridView1.GetType();
  PropertyInfo pi = dgvType.GetProperty("DoubleBuffered",
    BindingFlags.Instance | BindingFlags.NonPublic);
  pi.SetValue(dataGridView1, value, null);
}