簡體   English   中英

刪除數據表中的行時,DataGridView中無法捕獲的異常

[英]Uncatchable exception in DataGridView when deleting rows in datatable

我有一個數據表,其中根據互聯網上可用的數據添加行。 每次添加一行時,我都會在該行上添加一個時間戳。 這已經工作了很多年,數百名用戶都沒有發生任何錯誤。 現在,我希望根據數據的使用期限從數據表中刪除行。 我有一個計時器,它會觸發每個用戶定義的時間間隔,然后搜索所有較舊的行並將其刪除。 問題是,我收到的各種錯誤似乎都在改變,即使我在所有方法上都嘗試了catch語句,也未捕獲到錯誤。 僅在program.cs中整個應用程序的錯誤捕獲中捕獲該錯誤,這些錯誤是“退出錯誤:未將對象引用設置為對象的實例。在System.Windows.Forms.DataGridViewCell.PaintWork,或退出錯誤:索引超出范圍,必須為非負數且小於集合的大小參數名稱:System.Collections.ArrayList.get_Item(Int32 index)處的索引

或退出錯誤:對象引用未設置為對象的實例。 在System.Windows.Forms.DataGridViewTextBoxCell.PaintPrivate

但是其余的錯誤中沒有有用的信息。 這是代碼:

    public void ageTimer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
    {
        try
        {
            spotAge = Convert.ToDouble(Properties.Settings.Default.SpotAge);

            //Select all rows in datatable where the age is older than spotAge and delete them.
            //date is stored in dt as 20:12:2017: 21:49:02 derived from DateTime.UtcNow.ToString("dd:MM:yyyy: HH:mm:ss")

            //spotTime is the time from the table

            DateTime spotTime;
            dt.AcceptChanges();
            var rowCount = dt.Rows.Count;

            for (int i = rowCount -1; i >= 0; i--)
            {
                DataRow dr = dt.Rows[i];

                spotTime = DateTime.ParseExact(Convert.ToString(dr["date"]), "dd:MM:yyyy: HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);

                if (spotTime.AddMinutes(spotAge) <= DateTime.UtcNow)
                {
                    dr.Delete();

                }
            }

            dt.AcceptChanges();

            dataGridView1.Update();
            dataGridView1.Refresh();
            dataGridView1.FirstDisplayedScrollingRowIndex = 0;
        }

        catch (Exception x)
        {

        }
    }

現在有趣的是,在我的系統上這根本不會崩潰。 但是,如果我在調試模式下運行Visual Studio,它將可以。 它還會在少數用戶上崩潰。 但不是所有人。

我嘗試了相同的代碼,除了我總是會只刪除一行並且它工作得很好。 我嘗試刪除除第一行,前兩行之外的所有行,但仍然崩潰。

根據下面的評論指出計時器在單獨的線程上運行,我添加了以下內容:

    public void ageTimer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
    {
        DeleteRows("");
    }

上面的代碼現在具有以下內容:

private void DeleteRows(string details)
{
  if (InvokeRequired)
  {
     this.Invoke(new Action<string>(DeleteRows), new object[] { details});
     return;
  }

其余代碼如上。 這樣可以徹底解決問題。 非常感謝!

請再次閱讀您的問題。 這已經工作了好幾年了。 現在它不起作用,因為您添加了計時器,並在新的單獨線程中運行。 這可能是比賽條件。 顯然,dt是一種共享資源,在多線程環境中不能正確使用。 假設dt是數據網格視圖的源,在一種情況下,用戶可能正在使用它(只需滾動就足以從dt中讀取內容,以便繪制新的可見行-因此,我想您會從那里得到PaintWork錯誤,因為狀態在平均時間內被計時器事件處理程序更改了)。 想象一下,用戶從網格中刪除了行,這反映了基礎源dt ,但是,您的計時器剛好在剛才刪除了這些行,並且您獲得了索引超出范圍的異常。

除了可以在計時器事件處理程序中使用dt ,還可以嘗試制作它的副本dt_copy (只是注意不要制作淺表副本)。 進行更改,完成后,只需將該副本綁定為新的datagridview源即可,一切都會很好。

另一種可能執行起來也更快的方法是調用存儲過程並直接由數據庫刪除,並在調用返回后立即刷新dt (只需重新填充dt )。

在這兩種情況下,取決於刪除的速度,您應該檢查'dt'是否臟(同時由用戶更新),並且可能希望合並這些更改,以免丟失。

這里的問題是,您要在for循環中調用delete row.delete語句。 這是在操縱行集合的長度,從而使索引超出綁定異常范圍。

來自msdn的一句話:

遍歷DataRowCollection對象時,不應在foreach循環中調用Delete。 刪除修改集合的狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM