【问题标题】:Add rows to DataGridView without freezing GUI在不冻结 GUI 的情况下向 DataGridView 添加行
【发布时间】:2018-04-30 06:40:24
【问题描述】:

我想显示一个表格。表格数据必须预先计算,计算量大。结果表也很长。 我想提供对部分数据的访问,而另一部分是在后台计算的。

我为计算编写了后台工作程序,为显示编写了 DataGridView。有时工作人员通过 ProgressChangedEvent 提交新行。我试图在底部添加这些行。 当我尝试在底部添加新行时,我的问题就开始了。我的 UI 卡住了。

这是我初始化 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));
}

我认为这个问题是因为添加一行会重新绘制表格。 但我没有找到用于 BindingList 的 AddRange 或临时停止渲染的机制。

有什么建议吗?

【问题讨论】:

  • 看看this post也可以实现IBindingList,它可以停止引发ListChanged事件。
  • 看起来很有趣。感谢指导。

标签: c# winforms user-interface datagridview


【解决方案1】:

通过向列表中添加新项目,BindingList 会引发 ListChanged,从而导致更新 DataGridView。为了更有效地更新DataGridView,您可以选择停止引发BindingListListChanged 事件。这样,您可以在添加项目之前将其关闭,然后在将一组项目添加到列表后将其打开并引发事件。

这是一个支持打开/关闭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 中的更改,启用该事件并引发它:

list.EnableChangeNotifications = true;
list.ResetBindings();

【讨论】:

  • 这是完美的解决方案。唯一一个不需要的视觉效果有位置(每次选择的列重置为 0)。但这不是问题。
  • 可以在ResetBindings列表之前存储选中的单元格索引,在ResetBindings之后再次设置。
【解决方案2】:

尝试将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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 2012-02-07
    相关资源
    最近更新 更多