Vb.net 为PropertyGrid-.NET更改多个属性中的一个属性-

Vb.net 为PropertyGrid-.NET更改多个属性中的一个属性-,vb.net,propertygrid,uitypeeditor,Vb.net,Propertygrid,Uitypeeditor,如何仅重写控件的一个EditValue函数,同时保持该控件的所有其他属性可用?当我将单个控件指定给PropertyGrid的SelectedObject属性时,我将获得该控件的所有属性。为了覆盖一个属性,我想创建一个属性包装类,它将像以前一样显示所有控件,包括自定义EditValue函数。但是我发现我必须在包装器类中定义所有属性,否则我只能通过自定义EditValue函数查看属性。这似乎很不切实际,一定有更简单的办法。 我需要这样做,因为我想捕获用户可以指定的背景图像的文件名。 捕获名称的代码运

如何仅重写控件的一个EditValue函数,同时保持该控件的所有其他属性可用?当我将单个控件指定给PropertyGrid的SelectedObject属性时,我将获得该控件的所有属性。为了覆盖一个属性,我想创建一个属性包装类,它将像以前一样显示所有控件,包括自定义EditValue函数。但是我发现我必须在包装器类中定义所有属性,否则我只能通过自定义EditValue函数查看属性。这似乎很不切实际,一定有更简单的办法。 我需要这样做,因为我想捕获用户可以指定的背景图像的文件名。 捕获名称的代码运行良好,这里是一个很好的度量:

    Friend Class CatchFileName : Inherits UITypeEditor

        Public Overrides Function GetEditStyle(context As ITypeDescriptorContext) As UITypeEditorEditStyle
            Return UITypeEditorEditStyle.Modal
        End Function

        Public Overrides Function EditValue(context As ITypeDescriptorContext,
                                provider As IServiceProvider, value As Object) As Object
            Dim ofd As New OpenFileDialog() With {.Filter = "Image Files|*.bmp;*.jpg;*.jpeg,*.gif;*.png;*.ewf;*.wmf;*.ico"}
            If (ofd.ShowDialog() = DialogResult.OK) Then
                DirectCast(context.Instance, FormPropertiesWrapper)._BackgroundImageName =
                   Path.GetFileName(ofd.FileName) ' Strip path
                Return Image.FromFile(ofd.FileName)
            End If
            Return MyBase.EditValue(context, provider, value)
        End Function
    End Class

    <Description("Defines a form's background image."), Category("Display")>
    <Editor(GetType(CatchFileName), GetType(System.Drawing.Design.UITypeEditor))>
    Public Property BackgroundImage() As Image
    Get
      Return _Form.BackgroundImage
    End Get
    Set(ByVal Value As Image)
      _Form.BackgroundImage = Value
    End Set
    End Property

Friend类CatchFileName:继承UITypeEditor
公共重写函数GetEditStyle(作为ITypeDescriptorContext的上下文)作为UITypeEditorEditStyle
返回UITypeEditorEditStyle.Modal
端函数
公共重写函数EditValue(上下文为ITypeDescriptorContext,
提供程序作为IServiceProvider,值作为对象)作为对象
使用{.Filter=“Image Files |*.bmp;*.jpg;*.jpeg,*.gif;*.png;*.ewf;*.wmf;*.ico”}将ofd作为新的OpenFileDialog()进行调整
如果(ofd.ShowDialog()=DialogResult.OK),则
DirectCast(context.Instance,FormPropertiesWrapper)。\u BackgroundImageName=
Path.GetFileName(ofd.FileName)'条带路径
返回Image.FromFile(ofd.FileName)
如果结束
返回MyBase.EditValue(上下文、提供程序、值)
端函数
末级
公共属性BackgroundImage()作为图像
得到
返回_Form.BackgroundImage
结束
设置(ByVal值作为图像)
_Form.BackgroundImage=值
端集
端属性

_表单在包装类FormPropertiesWrapper中声明为表单。PropertyGrid使用组件的来确定网格中通过显示的内容。您可以创建一个从GetProperties方法派生并重写该方法的包装器类,以提供一个新的包装器类,其中包含指向您的
CatchFileName
类的

我修改了您的
CatchFileName
类,使其能够处理名为
IBackgroundImageName
的接口,该接口需要在包装控件中实现。此包装器将与实现
BackgroundImageProxyWrapper.IBackgroundImageName
的任何控件一起使用。这样,图像名称存储在控件中而不是包装器中

Imports System.ComponentModel
Imports System.Drawing.Design
Imports System.IO

Friend Class BackgroundImageProxyWrapper : Inherits CustomTypeDescriptor
  Private Sub New(source As IBackgroundImageName)
    MyBase.New(TypeDescriptor.GetProvider(source).GetTypeDescriptor(source))
    SourceControl = source
  End Sub

  Public Shared Function Wrap(Of T As {Control, IBackgroundImageName})(source As T) As BackgroundImageProxyWrapper
    Return New BackgroundImageProxyWrapper(source)
  End Function

  Public ReadOnly Property SourceControl As IBackgroundImageName

  Public Overrides Function GetProperties() As PropertyDescriptorCollection
    Return GetProperties(Nothing)
  End Function

  Public Overrides Function GetProperties(attributes() As Attribute) As PropertyDescriptorCollection
    Dim ret As PropertyDescriptorCollection
    ret = New PropertyDescriptorCollection(New PropertyDescriptor() {}, False)
    For Each pd As PropertyDescriptor In MyBase.GetProperties(attributes)
      If pd.Name.Equals("BackgroundImage") Then
        ' substitute a PropertyDescriptor that includes the EditorAttribute
        Dim attribs As New List(Of Attribute)(pd.Attributes.Count + 1)
        Dim editorType As Type = GetType(EditorAttribute)
        ' 1st remove any previous editor attribute
        For Each attrib As Attribute In pd.Attributes
          If attrib.GetType IsNot editorType Then
            attribs.Add(attrib)
          End If
        Next
        attribs.Add(New EditorAttribute(GetType(CatchFileName), GetType(UITypeEditor)))
        pd = TypeDescriptor.CreateProperty(pd.ComponentType, pd, attribs.ToArray())
      End If
      ret.Add(pd)
    Next
    Return ret
  End Function

  Private Class CatchFileName : Inherits UITypeEditor

    Public Overrides Function GetEditStyle(context As ITypeDescriptorContext) As UITypeEditorEditStyle
      Return UITypeEditorEditStyle.Modal
    End Function

    Public Overrides Function EditValue(context As ITypeDescriptorContext,
                            provider As IServiceProvider, value As Object) As Object
      Dim ofd As New OpenFileDialog() With {.Filter = "Image Files|*.bmp;*.jpg;*.jpeg,*.gif;*.png;*.ewf;*.wmf;*.ico"}
      If (ofd.ShowDialog() = DialogResult.OK) Then
        DirectCast(context.Instance, BackgroundImageProxyWrapper).SourceControl.BackgroundImageName =
           Path.GetFileName(ofd.FileName) ' Strip path
        Return Image.FromFile(ofd.FileName)
      End If
      Return MyBase.EditValue(context, provider, value)
    End Function
  End Class

  Public Interface IBackgroundImageName
    Property BackgroundImageName As String
  End Interface
End Class
用法示例:

Public Class Form1
  Implements BackgroundImageProxyWrapper.IBackgroundImageName
  Private Property BackgroundImageName As String Implements BackgroundImageProxyWrapper.IBackgroundImageName.BackgroundImageName

  Private Sub BtnSetForm_Click(sender As Object, e As EventArgs) Handles BtnSetForm.Click
    PropertyGrid1.SelectedObject = BackgroundImageProxyWrapper.Wrap(Me)
  End Sub
End Class

编辑:更通用的版本,可用于任何控件。文件名存储在控件的标记属性中

Friend Class BackgroundImageProxyWrapper : Inherits CustomTypeDescriptor
  Public Sub New(source As Control)
    MyBase.New(TypeDescriptor.GetProvider(source).GetTypeDescriptor(source))
    SourceControl = source
  End Sub

  Public ReadOnly Property SourceControl As Control

  Public Overrides Function GetProperties() As PropertyDescriptorCollection
    Return GetProperties(Nothing)
  End Function

  Public Overrides Function GetProperties(attributes() As Attribute) As PropertyDescriptorCollection
    Dim ret As PropertyDescriptorCollection
    ret = New PropertyDescriptorCollection(New PropertyDescriptor() {}, False)
    For Each pd As PropertyDescriptor In MyBase.GetProperties(attributes)
      If pd.Name.Equals("BackgroundImage") Then
        ' substitute a PropertyDescriptor that includes the EditorAttribute
        Dim attribs As New List(Of Attribute)(pd.Attributes.Count + 1)
        Dim editorType As Type = GetType(EditorAttribute)
        ' 1st remove any previous editor attribute
        For Each attrib As Attribute In pd.Attributes
          If attrib.GetType IsNot editorType Then
            attribs.Add(attrib)
          End If
        Next
        attribs.Add(New EditorAttribute(GetType(CatchFileName), GetType(UITypeEditor)))
        pd = TypeDescriptor.CreateProperty(pd.ComponentType, pd, attribs.ToArray())
      End If
      ret.Add(pd)
    Next
    Return ret
  End Function

  Private Class CatchFileName : Inherits UITypeEditor

    Public Overrides Function GetEditStyle(context As ITypeDescriptorContext) As UITypeEditorEditStyle
      Return UITypeEditorEditStyle.Modal
    End Function

    Public Overrides Function EditValue(context As ITypeDescriptorContext,
                            provider As IServiceProvider, value As Object) As Object
      Dim ofd As New OpenFileDialog() With {.Filter = "Image Files|*.bmp;*.jpg;*.jpeg,*.gif;*.png;*.ewf;*.wmf;*.ico"}
      If (ofd.ShowDialog() = DialogResult.OK) Then
        DirectCast(context.Instance, BackgroundImageProxyWrapper).SourceControl.Tag =
           Path.GetFileName(ofd.FileName) ' Strip path
        Return Image.FromFile(ofd.FileName)
      End If
      Return MyBase.EditValue(context, provider, value)
    End Function
  End Class
End Class

非常感谢你详细的回答。我时不时地学到很多东西。我将不得不消化这篇文章,你将展示一个例子,其中Implements语句被添加到一个类中。当标准控件(如Forms.Panel控件)的属性必须编辑时,该示例会是怎样的?@DuxburyDutch,此包装器不是为非用户派生控件设置的。如果这不能满足您的使用需求,那么返回/检索BackgroundImageName将需要以不同的方式实现。GetProperties方法的基本逻辑将保持不变。我只是觉得将值存储在包装器中不方便,但如果您想要这样做,请删除
IBackgroundImageName
接口用法,并将我的更改还原为
CatchFileName
类,使其与您最初的更改相同。@DuxburyDutch,请参阅我的编辑。我添加了一个将文件名存储在控件的Tag属性中的版本。这将适用于任何控制。嗨@TnTinMn,再次感谢您的帮助。只是为了澄清一下,并不是我不想使用IBackgroundImageName接口,而是我认为除了使用包装类之外没有其他选择。。