PropertyGrid 滚动位置在设置时不改变

PropertyGrid scroll position not changing when set

我在 Windows Forms 应用程序中有一个 PropertyGrid。每当它的 SelectedObject 发生变化时,它会将其 VerticalScroll 值重置为 0。我需要它保持原样。下面的代码似乎没有做任何事情。我已经尝试了 PerformLayout 和许多其他解决方案,但都没有成功。有什么想法吗?

int pos = MyGrid.VerticalScroll.Value;
MyGrid.SelectedObject = SomeDifferentObject;
MyGrid.VerticalScroll.Value = pos;

VerticalScroll 属性 与 PropertyGrid class 无关。它引用 VScrollBar 控件的内部属性。 Scroll 事件永远不会上升。
VScrollBarSystem.Windows.Forms.PropertyGridInternal.PropertyGridView 控件的子控件,class 不能直接访问。

无论如何都可以得到它,将 PropertyGrid 转换为 Control 或忽略 PropertyGrid 的 Controls 属性 的 Browsable(false) 属性,然后找到 VScrollBar 子项,存储当前值然后在更改 SelectedObject 属性.
后再次设置它 请注意,这个新控件可以具有与以前不同数量的属性,滚动条将只设置在以前的位置。
为了更加 精确 ,您可以获得设置新 SelectedObject 之前和之后显示的属性数量,并执行 relative 滚动.

在这里,我通过 AccessibilityObject.Role 找到 PropertyGridView,也就是 AccessibleRole.Table,但您也可以通过其文本 ( "PropertyGridView"):

var vScroll = propertyGrid1.Controls.OfType<Control>()
    .Where(ctl => ctl.AccessibilityObject.Role == AccessibleRole.Table)
    .First().Controls.OfType<VScrollBar>().First();

var vScrollValue = vScroll.Value;
propertyGrid1.SelectedObject = [Some Other Object];
vScroll.Value = vScrollValue;

如果需要(如前所述),将滚动条重新定位在相同的相对位置,代码可能会变成:

BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;

var propGrid = propertyGrid1.Controls.OfType<Control>()
    .Where(ctl => ctl.AccessibilityObject.Role == AccessibleRole.Table).First();
var totalProperties = (int)propGrid.GetType().GetField("totalProps", flags).GetValue(propGrid);

var vScroll = propGrid.Controls.OfType<VScrollBar>().FirstOrDefault();
if (vScroll != null && totalProperties > 0) {
    var vRelativeScroll = vScroll.Value / (float)totalProperties;
    propertyGrid1.SelectedObject = this.trackBar2;

    totalProperties = (int)propGrid.GetType().GetField("totalProps", flags).GetValue(propGrid);
    vScroll.Value = (int)(vRelativeScroll * totalProperties);
}