【问题标题】:Derive PropertyGrid dropdown list from property that is an object class, not just a string从作为对象类的属性中派生 PropertyGrid 下拉列表,而不仅仅是字符串
【发布时间】:2020-03-20 00:15:54
【问题描述】:

如何在属性网格中拥有作为对象(不仅仅是字符串)下拉列表的属性?我走了这么远,但后来卡住了!考虑下面的代码:

Public Class mOrganisation

    Public Property ID as String
    Public Property Name as String

End Class

Public Class mSystem

    Public Property ID as string
    Public Property Name as String
    Public Property Developer as mOrganisation

     Public Overrides Function ToString() As String
        Return Name
    End Function

End Class

Public Class mGame

    Public Property ID as string
    Public Property Name as String

    <TypeConverter(GetType(SystemConverter))>
    Public Property System as mSystem

End Class

Public Class Main

    Public Systems as List(of mSystem) = [...list gatehring code here]

End Class


Public Class SystemConverter
Inherits TypeConverter

    Public Overrides Function GetStandardValuesSupported(ByVal context As ITypeDescriptorContext) As Boolean
        Return True
    End Function

    Public Overrides Function GetStandardValuesExclusive(ByVal context As ITypeDescriptorContext) As Boolean
        Return False
    End Function

    Public Overrides Function GetStandardValues(ByVal context As ITypeDescriptorContext) As TypeConverter.StandardValuesCollection
        Return New StandardValuesCollection(Main.Systems)
    End Function

End Class

mOrgnisation 只是为了给 mSystem 类引入一些复杂性。现在这段代码确实会下拉值:

但是当我选择一个值时,我得到一个 PropertyGrid 错误“'System.String' 类型的对象无法转换为'mSystem' 类型”

这让我陷入了困境,特别是尝试应用 Convert FromConvert To 的各种排列。但是,我找不到合适的解决方案。通过ConvertFrom 进行的一次尝试使下拉菜单加载非常缓慢,一次一个项目(我认为它正在为每个项目触发)。

我会制作一个自定义 UITypeEditor,但我找不到像标准下拉菜单那样获得 PropertyGrid 固有调整大小方法/句柄的方法(并尝试编写我自己的调整大小例程,但我认为它被证明是粘性和闪烁的,因为PropGrid+控件的交互)

实现这一目标的最佳/最优雅的方式是什么?

【问题讨论】:

    标签: .net propertygrid typeconverter uitypeeditor


    【解决方案1】:

    有一些方法可以告诉系统“从对象中挑选什么”

    1) 在 ComboBox 上使用 DisplayMemberPath:

    <ComboBox ItemsSource="{Binding Path=mSystem}" 
          DisplayMemberPath="Name"/>
    

    2) 在 ComboBox 上设置 ItemTemplate。这就像 #1,除了允许您定义要显示的模板:

    <ComboBox ItemsSource="{Binding Path=mSystem}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Green" BorderThickness="1" Padding="5">
                <TextBlock Text="{Binding Path=Name,StringFormat='Name: {0}'}" />
            </Border>
        </DataTemplate>
    </ComboBox.ItemTemplate>
    

    3) 将 DataTemplate 添加到 XAML 资源。这对于关联给定的类很有用:

    <UserControl xmlns:local="CLASS_CONTEXT_HERE">
    <UserControl.Resources>
        <DataTemplate DataType="local:mSystem">
            <TextBlock Text="{Binding Name}" />
        </DataTemplate>
    </UserControl.Resources>
    

    4)如果你想显示 NAME 和 ID :

    Public Overrides Function ToString() As String
        Return string.Format("{0} ({1})", Name, ID)
    End Function
    

    【讨论】:

    • 感谢您抽出时间来构建这个答案 SHoaib。它将证明对 WPF 场景很有用。我的错-没有提到我在winforms上+最终找到了自己的答案。不过,谢谢。
    【解决方案2】:

    最终放弃了 TypeConverter 并找到了解决方案。就像大多数编码噩梦一样,5 行简单的代码放在了正确的位置!关键是访问 PropertyGrid 内置的调整大小句柄。您可以调整下面的代码以包含处理自定义对象的构建,因为value 是任何对象。但是,为简单起见,下面的示例是一个字符串:

    Public Overrides ReadOnly Property IsDropDownResizable As Boolean
        Get
            Return True
        End Get
    End Property
    

    实现方法如下:

    第 1 步:创建新的 UITypeEditor

    这会将属性连接到自定义编辑器。 value 包含从属性传递的值。它可以是任何对象类型。因此,您可以将其传递给您的自定义控件,以通知其中的任何编辑功能。

    创建一个新类:

    Imports System.ComponentModel
    Imports System.Drawing.Design
    Imports System.Windows.Forms.Design
    
    Public Class TestUIEditor
        Inherits UITypeEditor
    
        ' Indicate that we display a dropdown.
        Public Overrides Function GetEditStyle(ByVal context As ITypeDescriptorContext) _
            As UITypeEditorEditStyle
    
            Return UITypeEditorEditStyle.DropDown
    
        End Function
    
        Public Overrides Function EditValue(ByVal context As ITypeDescriptorContext, ByVal provider As IServiceProvider, ByVal value As Object) As Object
    
            ' Get an IWindowsFormsEditorService object.
            Dim editor_service As IWindowsFormsEditorService = CType(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
            If editor_service Is Nothing Then
                Return MyBase.EditValue(context, provider, value)
            End If
    
            'Setup the editor
            Dim editorService As IWindowsFormsEditorService = Nothing
            If provider IsNot Nothing Then
                editorService = TryCast(provider.GetService(GetType(IWindowsFormsEditorService)), IWindowsFormsEditorService)
            End If
    
            If editorService IsNot Nothing Then
    
                Dim testUI As New TestPropGridUI(editorService)
                'Populate the existing value to the dropdown control
                testUI.Text = value
                'Drop down the control
                editorService.DropDownControl(testUI)
                'Update property value once dropdown closed
                value = testUI.Text
    
            End If
    
            Return value
    
        End Function
    
        Public Overrides ReadOnly Property IsDropDownResizable As Boolean
            Get
                'Ensures control is resizable
                Return True
            End Get
        End Property
    
    End Class
    

    第 2 步:创建您的自定义编辑器:

    在这个例子中,我刚刚使用了一个继承 TextBox 的自定义类。但是,您可以使用任何控件,甚至是自定义 UserControl。

    Imports System.Windows.Forms.Design
    
    Public Class TestPropGridUI
        Inherits TextBox
    
        ' The editor service displaying this control.
        Private m_EditorService As IWindowsFormsEditorService
    
        Public Sub New(ByVal editor_service As IWindowsFormsEditorService)
            MyBase.New()
    
            m_EditorService = editor_service
            Dock = DockStyle.Fill
    
        End Sub
    
        Public Sub returnPressed(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
    
            'Closes the dropdown when Enter pressed
            If e.KeyCode = Keys.Enter Then
                m_EditorService.CloseDropDown()
            End If
    
        End Sub
    
    End Class
    

    注意 m_EditorService.CloseDropDown。将其放在您希望下拉菜单自行关闭的任何位置(例如,在选择值之后)。

    第 3 步:告诉您的类属性使用自定义编辑器:

    Public Class TestObject
    
        Public Property ID as String
        Public Property Quantity as Integer
    
        <Editor(GetType(TestUIEditor), GetType(UITypeEditor))>
        Public Property TestText As String
    
    End Class
    

    就是这样!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多