【问题标题】:Winforms DataGridView in VirtualMode when to call AutoResizeColumn?在VirtualMode中Winforms DataGridView何时调用AutoResizeColumn?
【发布时间】:2012-03-22 02:53:40
【问题描述】:

我在表单上实现了DataGridView,并成功实现了VirtualMode。这会从本地缓存中检索单元格数据,并且在填充网格/分页等时似乎一切正常。我处理 DataGridView.CellValueNeeded 事件来填充单元格。

在 DataGridView 上,我将 AutoSizeColumnsMode 属性设置为 DataGridViewAutoSizeColumnsMode.DisplayedCells。我注意到在使用 VirtualMode 时,DataGridView 在填充单元格后似乎不尊重 AutoSizeColumnsMode。我检查了this article,但没有找到解决方案。

我最终想做的是不依赖AutoSizeColumnsMode 属性,而是调用.AutoResizeColumn() 方法somewhere 来调整大小,所以我最初自动调整列大小,但随后允许用户调整大小。

我尝试了以下方法,但效果有限或没有成功:

  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;
    }
    

    它可以正确调整列的大小,但必须在每个需要的单元格值上重复调用它似乎很奇怪。此外,我不能立即将其设置为 .None ,否则它将再次 StackOverFlowException 。因此,我不能允许用户调整列的大小。

  5. 如文章中所述,从我的.CellValueNeeded 处理程序调用.UpdateCellValue() 也会抛出StackOverFlowException

那么有没有可能在某个地方调用.AutoResizeColumn(),直到它溢出才会引发.CellValueNeeded?由于#4 似乎能够执行自动调整大小功能,因此我似乎也可以从某个地方手动调用它。

【问题讨论】:

    标签: c# winforms datagridview autoresize virtualmode


    【解决方案1】:

    我认为这可能是解决方案,尽管我仍然有兴趣听听其他人的意见。

    我继续查看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

    这似乎符合要求。用户将在初始加载时看到非常合适的列,并且可以从那里进行调整,而且我的大部分数据在行与行之间的长度相当,因此在大多数情况下不应截断或浪费空间。

    【讨论】:

      【解决方案2】:

      由于您声明您对其他人的评论感兴趣,因此我整理了一种稍微不同的方法来使用虚拟数据网格自动调整列大小。

      初始 AutoResizeColumns 调用放置在 Shown 事件之后,以便初始化和显示表单和子组件。此外,通过连接 DataGridView Scroll 事件来调整大小,而不是 RowPostPaint,这应该会稍微更有效,因为此事件触发频率较低,而且我认为它与您引用的 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;
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2010-09-18
        • 2011-02-20
        • 1970-01-01
        • 2015-01-12
        • 1970-01-01
        • 2014-03-17
        • 1970-01-01
        • 2011-09-27
        • 1970-01-01
        相关资源
        最近更新 更多