Results 1 to 2 of 2

Thread: Custom property editor (UITypeEditor) not working properly with class

Threaded View

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Apr 2007
    Location
    The Netherlands
    Posts
    5,070

    Custom property editor (UITypeEditor) not working properly with class

    Hi,


    I want to give some property of a custom control I created a custom property editor window. What I mean by that is that, in the property grid, the property is not directly editable but has a "[...]" button next to it. Clicking that button will open an editor form which allows you to edit the value.


    In the screenshot you can see a very simple example, where 'MyProperty' is just a String property on a custom TextBox class:
    vb.net Code:
    1. Imports System.ComponentModel
    2. Imports System.Drawing.Design
    3.  
    4. Public Class CustomTextBox
    5.     Inherits TextBox
    6.  
    7.     Private _MyProperty As String
    8.     <Editor(GetType(CustomPropertyEditor), GetType(UITypeEditor))> _
    9.     Public Property MyProperty() As String
    10.         Get
    11.             Return _MyProperty
    12.         End Get
    13.         Set(ByVal value As String)
    14.             _MyProperty = value
    15.         End Set
    16.     End Property
    17.  
    18. End Class
    The CustomPropertyEditor class, which is set as this property's EditorAttribute, is slightly involved, so I left out some of the irrelevant parts. It inherits from UITypeEditor and takes care of showing a modal form when the [...] button is clicked.
    vb.net Code:
    1. Imports System.Drawing
    2. Imports System.Drawing.Design
    3. Imports System.Windows.Forms
    4. Imports System.Windows.Forms.Design
    5. Imports System.ComponentModel
    6.  
    7. Public Class CustomPropertyEditor
    8.     Inherits System.Drawing.Design.UITypeEditor
    9.  
    10.     Private m_editorForm As TextEditorForm
    11.  
    12.     Private Function GetEditControl(ByVal PropertyName As String, ByVal CurrentValue As Object) As System.Windows.Forms.Control
    13.         Dim str As String = CStr(CurrentValue)
    14.         m_editorForm = New TextEditorForm()
    15.         m_editorForm.Value = str
    16.         Return m_editorForm
    17.     End Function
    18.  
    19.     Private Function GetEditedValue(ByVal EditControl As System.Windows.Forms.Control, ByVal PropertyName As String, ByVal OldValue As Object) As Object
    20.         If m_editorForm Is Nothing _
    21.         OrElse m_editorForm.DialogResult = DialogResult.Cancel Then
    22.             Return OldValue
    23.         Else
    24.             Return m_editorForm.Value
    25.         End If
    26.     End Function
    27.  
    28.     Public Overrides Function GetEditStyle(ByVal context As System.ComponentModel.ITypeDescriptorContext) As UITypeEditorEditStyle
    29.         Return UITypeEditorEditStyle.Modal
    30.     End Function
    31.  
    32.     'some stuff omitted
    33.  
    34. End Class
    Basically, the GetEditorControl function returns a new instance of the TextEditorForm (which is the modal form you can see on the screenshot, used to edit the property), but first sets its Value property (the text in its TextBox) to the current value of the MyProperty property.
    The GetEditedValue function is used to return the result of the edit (the text in the textbox, which is the Value property) back to the property.


    This works just fine. I can edit the String property and the result is stored and shown forever. Great.


    Then, I wanted something more involved. Instead of just a String property, I have a property that returns an instance of some nested class, which in turn carries a whole load of other properties.

    So now the CustomTextbox class becomes a little more involved. It has one nested class (called NestedClass), with two string properties (as an example). It exposes an instance of this class via a NestedClassInstance property.
    vb.net Code:
    1. Imports System.ComponentModel
    2. Imports System.Drawing.Design
    3.  
    4. Public Class CustomTextBox
    5.     Inherits TextBox
    6.  
    7.     Public Sub New()
    8.         _NestedClassInstance = New NestedClass()
    9.     End Sub
    10.  
    11.     Private _NestedClassInstance As NestedClass
    12.     <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
    13.     <Editor(GetType(CustomPropertyEditor), GetType(UITypeEditor))> _
    14.     Public Property NestedClassInstance() As NestedClass
    15.         Get
    16.             Return _NestedClassInstance
    17.         End Get
    18.         Set(ByVal value As NestedClass)
    19.             _NestedClassInstance = value
    20.         End Set
    21.     End Property
    22.  
    23.     Public Class NestedClass
    24.  
    25.         Private _MyProperty1 As String
    26.         Public Property MyProperty1() As String
    27.             Get
    28.                 Return _MyProperty1
    29.             End Get
    30.             Set(ByVal value As String)
    31.                 _MyProperty1 = value
    32.             End Set
    33.         End Property
    34.  
    35.         Private _MyProperty2 As String
    36.         Public Property MyProperty2() As String
    37.             Get
    38.                 Return _MyProperty2
    39.             End Get
    40.             Set(ByVal value As String)
    41.                 _MyProperty2 = value
    42.             End Set
    43.         End Property
    44.     End Class
    45.  
    46. End Class
    This time, the Editor attribute is set on the NestedClassInstance property, because I want to edit that property directly via the editor form.

    (Please note that, if I get rid of the Editor attribute, and replace it with an ExpandableObject TypeConverter attribute, (so that the property is expandable in the property grid), I can get and set the two string properties just fine, simply using the property grid, and they are stored like they should be.)


    Now, in order for my editor form to be able to change this NestedClassInstance property, I gave it a PropertyGrid control instead of the TextBox. I also had it take an instance of the CustomTextBox.NestedClass in its constructor, so that the PropertyGrids SelectedObject can be set to that instance, so that it's editable. Finally, there is now a NestedClassInstance on the editor form as well, which simply returns the instance of the NestedClass which was passed again.
    vb.net Code:
    1. Imports System.Windows.Forms
    2.  
    3. Public Class TextEditorForm
    4.  
    5.     Private _NestedClassInstance As CustomTextBox.NestedClass
    6.     Public Sub New(ByVal nc As CustomTextBox.NestedClass)
    7.  
    8.         ' This call is required by the Windows Form Designer.
    9.         InitializeComponent()
    10.  
    11.         ' Add any initialization after the InitializeComponent() call.
    12.         _NestedClassInstance = nc
    13.         PropertyGrid1.SelectedObject = nc
    14.     End Sub
    15.  
    16.     Public ReadOnly Property NestedClassInstance() As CustomTextBox.NestedClass
    17.         Get
    18.             Return _NestedClassInstance
    19.         End Get
    20.     End Property
    21.  
    22.     Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click
    23.         Me.DialogResult = System.Windows.Forms.DialogResult.OK
    24.         Me.Close()
    25.     End Sub
    26.  
    27.     Private Sub Cancel_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel_Button.Click
    28.         Me.DialogResult = System.Windows.Forms.DialogResult.Cancel
    29.         Me.Close()
    30.     End Sub
    31.  
    32. End Class
    Simple enough I hope.


    Now finally, I also needed a slight change in the CustomPropertyEditor UITypeEditor, mainly just to pass the CurrentValue (cast to a NestedClass class) to the editor form, and to get it back again:
    vb.net Code:
    1. Imports System.Drawing
    2. Imports System.Drawing.Design
    3. Imports System.Windows.Forms
    4. Imports System.Windows.Forms.Design
    5. Imports System.ComponentModel
    6.  
    7. Public Class CustomPropertyEditor
    8.     Inherits System.Drawing.Design.UITypeEditor
    9.  
    10.     Private m_editorForm As TextEditorForm
    11.  
    12.     Private Function GetEditControl(ByVal PropertyName As String, ByVal CurrentValue As Object) As System.Windows.Forms.Control
    13.         Dim nestedClass = TryCast(CurrentValue, CustomTextBox.NestedClass)
    14.         If nestedClass IsNot Nothing Then
    15.             m_editorForm = New TextEditorForm(nestedClass)
    16.             Return m_editorForm
    17.         Else
    18.             Return Nothing
    19.         End If
    20.     End Function
    21.  
    22.     Private Function GetEditedValue(ByVal EditControl As System.Windows.Forms.Control, ByVal PropertyName As String, ByVal OldValue As Object) As Object
    23.         If m_editorForm Is Nothing _
    24.         OrElse m_editorForm.DialogResult = DialogResult.Cancel Then
    25.             Return OldValue
    26.         Else
    27.             Return m_editorForm.NestedClassInstance
    28.         End If
    29.     End Function
    30.  
    31.     Public Overrides Function GetEditStyle(ByVal context As System.ComponentModel.ITypeDescriptorContext) As UITypeEditorEditStyle
    32.         Return UITypeEditorEditStyle.Modal
    33.     End Function
    34.  
    35. End Class


    Now when I click the button in the property grid, I get the new editor form with PropertyGrid control, which shows my two properties:


    So far so good. I can change the properties on the editor form, press the OK button, and they seem to be stored. When I open the editor form again, the changes were persisted.

    However...

    When I build the solution, close the Form1 designer file, and then re-open it (so that it's reloaded), then the changes are gone! It seems they are not persisted after all, at least not in the form designer file I guess.

    Also, when I make a change, Visual Studio doesn't seem to 'notice' it, as it does not tell me that the Form1.vb file has changed, so I can't even save it before closing it. (It doesn't get the asterisk * after it's name indicating an unsaved change).

    As I said before: if I get rid of the whole custom UITypeEditor thingy, and just edit the properties from the property grid, it works fine. Then the changes are persisted even after building.


    Am I missing something? Am I doing something fundamentally wrong? I can't really see the difference in using a String as the type to edit, or some custom class which in turn hosts some other properties. A String is just another class, right? So where's the difference?

    Note also that I am already setting the DesignerSerializationVisibility attribute of the NestedClassInstance to Content, which, in my understanding, should ensure that any changes to that property are stored in the designer file. Still, it doesn't work.


    Anyone? Thanks for any help!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width