2

我已经DataGridView在我的表格上实施了 a 并成功实施VirtualMode。这将从本地缓存中检索单元格数据,并且在填充网格/分页等时一切似乎都正常工作。我处理DataGridView.CellValueNeeded事件以填充单元格。

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

我最终想做的是不依赖该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;
    }
    

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

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

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

4

2 回答 2

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在初始数据加载之前进行设置。

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

于 2012-03-05T02:32:43.203 回答
0

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

初始 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;
        }
    }
}
于 2017-03-26T05:56:15.150 回答