.NET 3.5 WinForms - DataGridView在refresh()上崩溃。这是一个错误吗?

时间:2011-05-23 19:15:28

标签: c# .net-3.5 datagridview

这是一个多线程场景。

  1. 主线程处理应用程序和UI事件,并启动一个新线程来执行一些后台操作。
  2. “background”线程将文件中的数据加载到强类型数据集的数据表中。 DataGridView绑定到DataTable
  3. 数据准备就绪后,“背景”主题将调用表单上refresh()的{​​{1}}函数。
  4. 如果有更多行,那么适合一个屏幕并显示垂直滚动条:网格崩溃。始终显示新的数据线。仅当有足够的行显示滚动条时才会出现错误(请参见下图)。

    Sample image of DataGridView crash

    我使用的是.NET 3.5。在Windows XP中,它会崩溃整个应用程序。在Win 7(64位)上,只有网格没有响应,但是一旦我调整窗口大小,就会出现滚动条,一切都很好。

    代码的相关部分如下。

    表单的.cs文件中的网格刷新操作:

    DataGridView

    “后台”主题中的更新部分:

        public void ThreadSafeRebindGrids()
        {
            SimpleCallBack callBackHandler = new SimpleCallBack(RebindGrids);
            this.BeginInvoke(callBackHandler);
        }
        public void RebindGrids()
        {
            gridCurrentResults.Refresh(); // The problematic DataGridView refresh()
            gridAllResults.Refresh();
        }
        public delegate void SimpleCallBack();
    

    与“背景”主题相关的对象直接引用 void Maestro32_SampleFinished(object sender, MeasurementEvents.SampleFinishedEventArgs e) { //--- Read new results ParentForm.ThreadSafeSetStatusInfo("Processing results for sample no. " + e.SampleNo.ToString() + "..."); CurrentMeasurement.ReadSpeResults(); // Updating the DataTable in the strongly typed DataSet (see below) ParentForm.ThreadSafeRebindGrids(); // Refresh the DataGridView ParentForm.ThreadSafeRefreshNumbers(); } DataSet)。 UiDataSourceDataTable)按以下方式更新:

    CurrentSamples

    /// <summary> /// Adds a new sample to the CurrentSamples table of the UiDataSet. /// </summary> /// <param name="sample">The new sample to be added to the table.</param> /// <param name="serial">The serial number of the sample being added</param> private void AddSampleToCurrentResults(SampleData sample, int serial) { UiDataSource.CurrentSamples.AddCurrentSamplesRow(serial, sample.MeasurementDate, (uint)Math.Round(sample.SampleCountSum), true, //--- Set the checkbox checked sample.LiveTime, sample.RealTime); } 选项:

    DataGridView

    如果我在某处犯了错误,请指出我。

    @ChrisF:

    我尝试删除 // // gridCurrentResults (generated) // this.gridCurrentResults.AllowUserToAddRows = false; this.gridCurrentResults.AllowUserToDeleteRows = false; this.gridCurrentResults.AllowUserToOrderColumns = true; this.gridCurrentResults.AllowUserToResizeRows = false; this.gridCurrentResults.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.gridCurrentResults.AutoGenerateColumns = false; this.gridCurrentResults.CausesValidation = false; this.gridCurrentResults.ColumnHeadersHeight = 25; this.gridCurrentResults.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { this.selectedCol, this.SampleNoCol, this.MeasuredValueCol, this.liveTimeCol, this.realTimeDataGridViewTextBoxColumn, this.AtTimeCol}); this.gridCurrentResults.DataMember = "CurrentSamples"; this.gridCurrentResults.DataSource = this.uiDataSource; this.gridCurrentResults.Location = new System.Drawing.Point(11, 24); this.gridCurrentResults.Margin = new System.Windows.Forms.Padding(8); this.gridCurrentResults.Name = "gridCurrentResults"; this.gridCurrentResults.RowHeadersVisible = false; this.gridCurrentResults.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; this.gridCurrentResults.ShowEditingIcon = false; this.gridCurrentResults.Size = new System.Drawing.Size(534, 264); this.gridCurrentResults.TabIndex = 0; this.gridCurrentResults.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.gridCurrentResults_CellContentClick); 语句,因为我的建议与您建议的完全相同。唯一的区别是数据绑定,它看起来像:

    refresh()

    我以类似的方式更新this.dataGridView.DataSource = this.dataSet; this.dataGridView.DataMember = "dataTable"; ,但是从另一个线程更新。

    但是,在我调整窗口大小之前,新数据行不会出现。

    这提出了如何从另一个线程正确更新dataTable的问题?

2 个答案:

答案 0 :(得分:4)

我猜这个问题与WinForms如何在STA模型中进行线程化有关。基本上,您访问的DataTable位于某处,这可能在我们上面看到的表单中。那么,当您从另一个线程更新DataTable时,哪个线程获取绑定所需的事件?可能是您更新它的线程,并且表单的线程不知道正在进行的更改。因此,您只需要调用对DataTable的任何调用到表单本身,因此它可以正确地接收事件:

this.Invoke(() => {
   // any calls involving DataTable
});

似乎倒退了,但在“企业”情况下请记住,您可能正在通过多个适配器访问该数据集。因此,您的更新线程将拥有自己的适配器,您的GUI也将拥有自己的适配器。另一种解决方案是使用BindingList,我相信这种情况具有线程兼容性,但不要引用我。

为了获得额外的功劳,这也可以在崩溃之前解释您的问题。通过从后台线程访问DataGridView,您可以进行跨线程操作。

答案 1 :(得分:0)

我不打电话:

    gridCurrentResults.Refresh(); // The problematic DataGridView refresh()
    gridAllResults.Refresh();

随着数据集变得越来越大,这些将逐渐变得越来越长。

我编写了一个使用DataGridView来显示mp3文件信息的应用程序。我将DataSource的{​​{1}}设置为DataGridView

DataTable

然后只需将新信息添加到this.dataGridView.DataSource = this.dataTable;

DataTable

这会自动更新this.dataTable.Rows.Add(row);