0

我有一个表单,其中一些控件根据 DataGridView 中当前显示的行(及其位置)进行更新。因此,在dataGridView1.VerticalScrollBar.ValueChanged事件中,我遍历所有行并检查它们是否显示。

所以这是滚动回顶部(通过鼠标滚轮)时的问题:

  • dataGridView1.VerticalScrollBar.Value0-> 好的
  • dataGridView1.FirstDisplayedCell.RowIndex0-> 好的
  • dataGridView1.FirstDisplayedScrollingRowIndex0-> 好的
  • dataGridView1.Rows[0].Displayed仍然false-> 嗯?
  • dataGridView1.GetRowDisplayRectangle(0, false)也是{0,0,0,0}-> ...?

检查https://referencesource.microsoft.com后,我意识到FirstDisplayedCell实际使用this.Rows.GetFirstRow(DataGridViewElementStates.Visible | DataGridViewElementStates.Frozen),这似乎有点不正确,还是我错了?我该如何解决这个问题,以便获得第一行的正确显示信息/矩形?

先感谢您!

代码:

public partial class Form1 : Form
{
    private List<Person> persons = new List<Person>()
    {
        {new Person("mike", 20) },
        {new Person("tim", 31) },
        {new Person("steven", 15) },
        {new Person("dave", 41) },
        {new Person("tom", 35) },
        {new Person("bob", 18) },
        {new Person("peter", 22) },
        {new Person("sarah", 55) },
        {new Person("robert", 69) },
        {new Person("andre", 23) },
    };
    public Form1()
    {
        this.InitializeComponent();
        this.dataGridView1.DataSource = new BindingSource(this.persons, null);

        if (typeof(DataGridView).GetProperty("VerticalScrollBar", BindingFlags.Instance | BindingFlags.NonPublic) is PropertyInfo pi &&
             pi.GetValue(this.dataGridView1, null) is ScrollBar sb)
        {
            sb.ValueChanged += this.Sb_ValueChanged;
        }
    }

    private void Sb_ValueChanged(object sender, EventArgs e)
    {
        int scrollValue = (sender as ScrollBar).Value;
        int index = this.dataGridView1.FirstDisplayedCell.RowIndex;
        int index2 = this.dataGridView1.FirstDisplayedScrollingRowIndex;
        DataGridViewRow row = this.dataGridView1.Rows[index];
        bool displayed = row.Displayed;
        Rectangle rect = this.dataGridView1.GetRowDisplayRectangle(index, false);
    }
}
4

1 回答 1

1

似乎DataGridViewRow直到滚动事件完成处理后,状态才会更新。这就是为什么在DataGridViewRow.Displayed向上滚动以显示以前未显示的行时属性显示为 false 的原因。

您可以使用一些技巧来排队一个方法,以便在滚动事件完成后使用Control.BeginInvoke立即运行。

此外,没有理由使用反射侵入 DataGridView 的 VerticalScrollBar。请改用DataGridView.Scroll 事件

以下是对代码的修改,以使用 DataGridView.Scroll 事件和 BeginInvoke 来显示行状态并显示在滚动事件中和事件之后立即获得的矩形值。

private void dataGridView1_Scroll(object sender, ScrollEventArgs e)
{
    if (e.ScrollOrientation == ScrollOrientation.VerticalScroll)
    {
        int scrollValue = e.NewValue;
        int index = this.dataGridView1.FirstDisplayedCell.RowIndex;
        int index2 = this.dataGridView1.FirstDisplayedScrollingRowIndex;
        DataGridViewRow row = this.dataGridView1.Rows[index];
        bool displayed = row.Displayed;
        Rectangle rect = this.dataGridView1.GetRowDisplayRectangle(index, false);

        Debug.WriteLine($"Scroll: index={index}, rect={rect}, state = {row.GetState(index)}");

        BeginInvoke(new Action(() =>
        {
            Rectangle r = dataGridView1.GetRowDisplayRectangle(index, false);
            Debug.WriteLine($"Invoked: index={index}, rect={r}, state = {row.GetState(index)}");
        }), null);
    }
}
于 2020-04-01T14:40:23.803 回答