2012-03-04 113 views
2

我在表單上實施了DataGridView併成功實施VirtualMode。這從本地緩存中檢索單元格數據,並且在填充網格/分頁等時全部顯示正常工作。我處理DataGridView.CellValueNeeded事件以填充單元格。VirtualMode中的WinForms DataGridView何時調用AutoResizeColumn?

在DataGridView上,我將AutoSizeColumnsMode屬性設置爲DataGridViewAutoSizeColumnsMode.DisplayedCells。我注意到在使用VirtualMode時,在填充單元格後DataGridView看起來並不尊重AutoSizeColumnsMode。我已檢查了this article但未找到解決方案。

我最終會做的是不依靠AutoSizeColumnsMode財產,而是調用.AutoResizeColumn()方法地方來調整,所以我最初自動調整列,但隨後允許用戶調整。

我試圖用有限的或者沒有成功如下:

  1. 設置DataGridView.AutoSizeColumnsMode.None。然後在我的 .CellValueNeeded處理

    private void dataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) 
    { 
        // ... Get cell value from cache 
        dataGridView.AutoResizeColumn(e.ColumnIndex, DataGridViewAutoSizeColumnMode.DisplayedCells); 
    } 
    

    這將引發StackOverFlowException大概是因爲它 多次提出.CellValueNeeded

  2. 嘗試完全相同的事情,除了在.CellFormatting 事件處理程序。得到了相同的StackOverFlowException

  3. 嘗試與不DataGridView.SuspendLayout/ResumeLayout

    private void dataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) 
    { 
        // ... Get cell value from cache 
        dataGridView.CellValueNeeded -= dataGridView_CellValueNeeded; 
        dataGridView.AutoResizeColumn(e.ColumnIndex, DataGridViewAutoSizeColumnMode.DisplayedCells); 
        dataGridView.CellValueNeeded += dataGridView_CellValueNeeded; 
    } 
    

    這讓所有的空白單元格,所以沒有用。

  4. 這實際上是一個有些工作,是有原因的,我不明白:

    private void dataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) 
    { 
        // ... Get cell value from cache 
        dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells; 
    } 
    

    它正確地調整大小列,但它似乎很奇怪有反覆調用它需要每一個單元格的值。此外,我不能立即將它設置爲。無權之後,或將再次StackOverFlowException。因此,我不能允許用戶調整列的大小。

  5. 如我在.CellValueNeeded處理文章中提到的調用.UpdateCellValue()也會拋出StackOverFlowException

那麼,是否可以調用.AutoResizeColumn()的地方,它不會提高.CellValueNeeded直到溢出?由於#4似乎有能力執行autosize函數,所以好像我也可以從某處手動調用它。

回答

2

我認爲這可能是解決方案,儘管我仍然有興趣聽聽其他人有什麼要說的。

我繼續看了DataGridView提出的一些其他事件,發現.RowPostPaint事件。我創建了以下處理:

private void dataGridView_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) 
{ 
    if (dataGridView.AllowUserToResizeColumns) //So not to run unnecessarily 
    { 
     return; 
    } 
    var lastIndex = dataGridView.Rows.GetLastRow(DataGridViewElementStates.Displayed); 
    if (e.RowIndex == lastIndex) //Only do on the last displayed row 
    { 
     dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells); 
     dataGridView.AllowUserToResizeColumns = true; // User has control from here on 
    } 
} 

這實現在初始數據負載的列的自動調整大小,則允許用戶從那裏重新大小。它只做一次,比每個單元格所需要的更好。在初始數據加載之前,我必須設置dataGridView.AllowUserToResizeColumns = false

這似乎符合法案。用戶在初始加載時會很好地看到列,並且可以從那裏調整,並且大多數數據在行與行之間具有可比較的長度,所以在大多數情況下,不應該截斷或浪費空間。

0

既然您聲明您對其他人的說法感興趣,那麼我已經爲如何在虛擬數據網格中使用自動列大小調整做了一個稍微不同的方法。

初始AutoResizeColumns調用放置在顯示事件之後,以便表單和子組件被初始化並顯示。此外,通過連接線調整大小,而不是RowPostPaint DataGridView的滾動事件,這應該是非常輕微更有效,因爲此事件不那麼頻繁,我認爲這很好地遵循連同參考MSDN你舉:

using System.Collections.Generic; 
using System.Windows.Forms; 

namespace DataGridViewTest 
{ 
    public partial class DataGridViewForm : Form 
    { 
     private List<string> dataSource; 

     public DataGridViewForm() 
     { 
      InitializeComponent(); 

      // Enable VirtualMode for dataGridView1 
      dataGridView1.VirtualMode = true; 

      // Wire CellValueNeeded event handler 
      dataGridView1.CellValueNeeded += DataGridView1_CellValueNeeded; 

      // Wire Scroll event handler 
      dataGridView1.Scroll += DataGridView1_Scroll; 

      // Wire form Shown event handler 
      this.Shown += DataGridViewForm_Shown; 
     } 

     private void DataGridViewForm_Shown(object sender, System.EventArgs e) 
     { 
      // Populate dataGridView1 here to avoid perception of a long form startup time 
      populateDataGridView(); 

      // Resize columns after the form is initialized and displayed on screen, 
      // otherwise calling this method won't actually have an effect on column sizes 
      dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells); 
     } 

     private void DataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) 
     { 
      // Set the triggering cell's value to the corresponding value from dataSource 
      e.Value = dataSource[e.RowIndex]; 
     } 

     private void DataGridView1_Scroll(object sender, ScrollEventArgs e) 
     { 
      // Resize columns again, but only if a vertical scroll just happened 
      if (e.ScrollOrientation == ScrollOrientation.VerticalScroll) 
      { 
       dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells); 
      } 
     } 

     private void populateDataGridView() 
     { 
      fetchIntoDataSource(); 

      associateDataSourceToDataGridView(); 
     } 

     private void fetchIntoDataSource() 
     { 
      dataSource = new List<string>(); 

      // Insert a test string into dataSource many times 
      for (int i = 0; i < 1000; i++) 
      { 
       dataSource.Add("test string"); 
      } 
     } 

     private void associateDataSourceToDataGridView() 
     { 
      // Synchronize dataGridView1.RowCount to dataSource.Count 
      // This is necessary for the CellValueNeeded event to fire 
      dataGridView1.RowCount = dataSource.Count; 
     } 
    } 
}