I have a PropertyGrid
in a Windows Forms application. Whenever its SelectedObject
changes, it resets its VerticalScroll
value to 0. I need it to remain where it was. The code below doesn't seem to do anything. I've tried PerformLayout
and a bunch of other solutions with no success. Any ideas?
int pos = MyGrid.VerticalScroll.Value;
MyGrid.SelectedObject = SomeDifferentObject;
MyGrid.VerticalScroll.Value = pos;
The VerticalScroll
property is not relevant for the PropertyGrid class. It references the internal properties of the VScrollBar
control. The Scroll event is never rised.
The VScrollBar
is child of the System.Windows.Forms.PropertyGridInternal.PropertyGridView
control, a class that is not directly accessible.
You can get it anyway, casting PropertyGrid to Control or ignoring the Browsable(false)
attribute of the PropertyGrid's Controls
property, then find the VScrollBar
child, store the current value then set it again after you have changed the SelectedObject
property.
Note that this new Control can have a different number of properties than the previous, the Scroll bar will just be set where it was before.
To be more precise, you could get the number of properties shown before and after the new SelectedObject
is set and perform a relative scroll.
Here, I find the PropertyGridView
by its AccessibilityObject.Role
which is AccessibleRole.Table
, but you can also find it by its Text ("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;
If you want (as previously described), reposition the scroll bar in the same relative position, the code might become:
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();
float relativeScroll = 0f;
if (vScroll != null && totalProperties > 0) {
relativeScroll = vScroll.Value / (float)totalProperties;
}
propertyGrid1.SelectedObject = [Some Other Object];
totalProperties = (int)propGrid.GetType().GetField("totalProps", flags).GetValue(propGrid);
vScroll.Value = (int)(relativeScroll * totalProperties);