【问题标题】:PropertyGrid control - modify the position of the central splitting vertical linePropertyGrid控件-修改中心分割竖线的位置
【发布时间】:2013-01-27 18:11:56
【问题描述】:

我在 WinForms (http://msdn.microsoft.com/en-us/library/aa302326.aspx) 中有一个 PropertyGrid 控件。现在我想将中间的垂直线更向左移动(它总是居中,但我的键很短,而值是路径,很长。默认情况下,控件将线放在中间,即使用户可以移动它。关于用户友好性,我想以编程方式将行更多地向左移动。我现在已经多次搜索 WinForms 设计器属性以及 PropertyGrid 控件的成员,但没有找到选项(也没有任何与之相关的事件)。

它是否因私密而隐藏/修改?我只是监督了吗? (在那种情况下,我真的很抱歉)否则我该怎么做?

【问题讨论】:

  • 你好,我给你的解决方案你测试了吗?
  • @CatalinM。我现在正在这样做。但是,我得到编译器消息,方法“GetValue”没有重载需要 1 个参数(在 GetInternalLabelWidth 中)。无论如何,谢谢你的努力

标签: c# .net winforms propertygrid


【解决方案1】:

是的,不幸的是,这需要一些基于反射的 hack 才能实现。 这是一个示例扩展类:

PropertyGridExtensionHacks.cs

using System.Reflection;
using System.Windows.Forms;

namespace PropertyGridExtensionHacks
{
    public static class PropertyGridExtensions
    {
        /// <summary>
        /// Gets the (private) PropertyGridView instance.
        /// </summary>
        /// <param name="propertyGrid">The property grid.</param>
        /// <returns>The PropertyGridView instance.</returns>
        private static object GetPropertyGridView(PropertyGrid propertyGrid)
        { 
            //private PropertyGridView GetPropertyGridView();
            //PropertyGridView is an internal class...
            MethodInfo methodInfo = typeof(PropertyGrid).GetMethod("GetPropertyGridView", BindingFlags.NonPublic | BindingFlags.Instance);
            return methodInfo.Invoke(propertyGrid, new object[] {});
        }

        /// <summary>
        /// Gets the width of the left column.
        /// </summary>
        /// <param name="propertyGrid">The property grid.</param>
        /// <returns>
        /// The width of the left column.
        /// </returns>
        public static int GetInternalLabelWidth(this PropertyGrid propertyGrid)
        {
            //System.Windows.Forms.PropertyGridInternal.PropertyGridView
            object gridView = GetPropertyGridView(propertyGrid);

            //protected int InternalLabelWidth
            PropertyInfo propInfo = gridView.GetType().GetProperty("InternalLabelWidth", BindingFlags.NonPublic | BindingFlags.Instance);
            return (int)propInfo.GetValue(gridView);
        }

        /// <summary>
        /// Moves the splitter to the supplied horizontal position.
        /// </summary>
        /// <param name="propertyGrid">The property grid.</param>
        /// <param name="xpos">The horizontal position.</param>
        public static void MoveSplitterTo(this PropertyGrid propertyGrid, int xpos)
        {
            //System.Windows.Forms.PropertyGridInternal.PropertyGridView
            object gridView = GetPropertyGridView(propertyGrid);

            //private void MoveSplitterTo(int xpos);
            MethodInfo methodInfo = gridView.GetType().GetMethod("MoveSplitterTo", BindingFlags.NonPublic | BindingFlags.Instance);
            methodInfo.Invoke(gridView, new object[] { xpos });
        }
    }
}

要移动拆分器位置,请使用 MoveSplitterTo 扩展方法。 使用 GetInternalLabelWidth 扩展方法获取拆分器的实际位置。请注意,我观察到,在分配 SelectedObject 并且未显示 PropertyGrid 之前,GetInternalLabelWidth 返回 (-1)。

使用示例:

using PropertyGridExtensionHacks;
//...

    private void buttonMoveSplitter_Click(object sender, EventArgs e)
    {
        int splitterPosition = this.propertyGrid1.GetInternalLabelWidth();
        this.propertyGrid1.MoveSplitterTo(splitterPosition + 10);
    }

【讨论】:

  • GetInternamLabelWith 在将 new object[]{} 添加为 GetValue 的第二个参数时可以正常工作,并且 MoveSplitterTo 也可以工作,但是由于某种原因第一次分配 SelectedObject 后它不能直接工作。
  • 不过非常感谢!当由 Form 构造函数调用时,设置不起作用,但是当使用 FormLoad 事件时,一切正常!伟大的工作;)
  • 好吧,我忘了提到我在构建示例时针对的是 4.5 版的 Net Framework。正如我在回答中所说,在未分配 SelectedObject 且未显示 PropertyEditor 之前,InternalLabelWith 返回 (-1)。
  • 这很好用,但我无法为此创建单元测试,因为拆分器位置始终为 (-1),即使在分配选定对象并调用以下方法 pg.Show(); pg.Invalidate(); pg.Update(); pg.Refresh(); pg.PerformLayout(); pg.BringToFront();
  • @CBenni 将宽度更改为一个像素并返回也可以确保网格和 MoveSplitter 将工作。
【解决方案2】:

这是一个不依赖于直接使用私有方法或反射的方法。但它仍然使用未记录的接口。

在 .NET 4.0 中,PropertyGrid.Controls 集合包含 4 个控件。 PropertyGrid.Controls.item(2) 是一个未记录的 PropertyGridView (与使用反射的答案相同)。属性PropertyGridView.LabelRatio 调整列的相对宽度。 LabelRatio 的范围看起来是 1.1 到 9。较小的值使左列更宽。

我知道在您最初显示控件之前设置LabelRatio 有效。但是,我不确定一旦控件已显示,您需要做什么才能使其生效。您可以通过 Google MoveSplitterTo 查找 .NET 源代码并查看 PropertyGridView 的源代码以获取更多详细信息。涉及到的计算和运算看起来有些复杂,我没有详细分析。

LabelRatio 最初设置为 2(即将可用的 PropertyGrid 宽度分成两半)。将其设置为 3 表示三分之一,4 表示四分之一。 代码需要导入 System.Reflection

Public Sub MoveVerticalSplitter(grid As PropertyGrid, Fraction As Integer)
    Try
        Dim info = grid.[GetType]().GetProperty("Controls")
        Dim collection = DirectCast(info.GetValue(grid, Nothing), Control.ControlCollection)

        For Each control As Object In collection
            Dim type = control.[GetType]()

            If "PropertyGridView" = type.Name Then
                control.LabelRatio = Fraction

                grid.HelpVisible = True
                Exit For
            End If
        Next

    Catch ex As Exception
        Trace.WriteLine(ex)
    End Try
End Sub

将 PropertyGrid 底部的描述窗格的大小更改为文本行

Public Sub ResizeDescriptionArea(grid As PropertyGrid, lines As Integer)
    Try
        Dim info = grid.[GetType]().GetProperty("Controls")
        Dim collection = DirectCast(info.GetValue(grid, Nothing), Control.ControlCollection)

        For Each control As Object In collection
            Dim type = control.[GetType]()

            If "DocComment" = type.Name Then
                Const Flags As BindingFlags = BindingFlags.Instance Or BindingFlags.NonPublic
                Dim field = type.BaseType.GetField("userSized", Flags)
                field.SetValue(control, True)

                info = type.GetProperty("Lines")
                info.SetValue(control, lines, Nothing)

                grid.HelpVisible = True
                Exit For
            End If
        Next

    Catch ex As Exception
        Trace.WriteLine(ex)
    End Try
End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    相关资源
    最近更新 更多