Fog Creek Software
Discussion Board




Welcome! and rules

Joel on Software

Problems Serializing Object Properties

Problems Serializing Object Properties

I wrote a customer Splitter control that mimics the splitter behavior in Macromedia products.  The splitter has several properties of intrinsic data types and two of a custom Appearance class.  The Appearance class is almost identical in design to the Infragistics.Win,Appearance class, if that helps explain my design goal.

The problem is the Visual Studio Designer will serialize the intrinsic data type properties of the Splitter but not the Appearance classes.  Example:

  Me.Splitter1 = New [CustomLibrary].Splitter
  ...
  '
  'Splitter1
  '
  ' No Appearance serialization here!!!
  Me.Splitter1.Location = New System.Drawing.Point(160, 0)
  Me.Splitter1.Name = "Splitter1"
  Me.Splitter1.ShowButton = False
  Me.Splitter1.Size = New System.Drawing.Size(8, 269)
  Me.Splitter1.Visible = False

Below is some code (edited for brevity).  Thanks in advance for any help.


Public Class Splitter

  Inherits System.Windows.Forms.Control

  Private Const DEFAULT_SHOW_BUTTON As Boolean = True

  Private WithEvents m_Appearance As New Appearance
  Private m_ShowButton As Boolean = DEFAULT_SHOW_BUTTON

  ' Appearance
  <Browsable(True), _
    Category("Appearance"), _
    DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _
    RefreshProperties(RefreshProperties.All)> _
  Public Property Appearance() As Appearance
      Get
        Return m_Appearance
      End Get
      Set(ByVal Value As Appearance)
        m_Appearance = Value
        Invalidate()
      End Set
  End Property

  <Browsable(False), _
    EditorBrowsable(EditorBrowsableState.Never)> _
  Public Sub ResetAppearance()
      m_Appearance = New Appearance
  End Sub

  Private Function ShouldSerializeAppearance () As Boolean
      Return True
  End Function

  ' ShowButton
  <Browsable(True), _
    Category("Appearance"), _
    DefaultValue(DEFAULT_SHOW_BUTTON), _
    Description("Gets/sets the visiblity of the collapse button."), _
    DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
  Public Property ShowButton() As Boolean
      Get
        Return m_ShowButton
      End Get
      Set(ByVal Value As Boolean)
        m_ShowButton = Value
        Invalidate()
      End Set
  End Property

End Class



<Serializable(), _
TypeConverter(GetType(AppearanceConverter))> _
Public Class Appearance

  Private DEFAULT_BACK_COLOR As Color = Color.Empty
  Private DEFAULT_FONT As Font

  Public Event Changed()

  Private m_BackColor As Color = DEFAULT_BACK_COLOR
  Private m_Font As Font = DEFAULT_FONT


  ' BackColor
  <Category("Appearance"), _
    Description("The primary color used to fill the background."), _
    DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), _
    RefreshProperties(RefreshProperties.All)> _
  Public Property BackColor() As Color
      Get
        Return m_BackColor
      End Get
      Set(ByVal Value As Color)
        m_BackColor = Value
        OnChanged()
      End Set
  End Property


  ' Font
  <Category("Appearance"), _
    Description("."), _
    DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
  Public Property Font() As Font
      Get
        Return m_Font
      End Get
      Set(ByVal Value As Font)
        m_Font = Value
        OnChanged()
      End Set
  End Property


  <Browsable(False), _
    EditorBrowsable(EditorBrowsableState.Never)> _
  Public Sub ResetBackColor()
      BackColor = DEFAULT_BACK_COLOR
  End Sub


  <Browsable(False), _
    EditorBrowsable(EditorBrowsableState.Never)> _
  Public Sub ResetFont()
      Font = DEFAULT_FONT
  End Sub


  <Browsable(False), _
    EditorBrowsable(EditorBrowsableState.Never)> _
  Public Function ShouldSerializeBackColor() As Boolean
      Return Not BackColor.Equals(DEFAULT_BACK_COLOR)
  End Function


  <Browsable(False), _
    EditorBrowsable(EditorBrowsableState.Never)> _
  Public Function ShouldSerializeFont() As Boolean
      Return Not Font.Equals(DEFAULT_FONT)
  End Function

End Class


Public Class AppearanceConverter

  Inherits ExpandableObjectConverter

  Public Overloads Overrides Function CanConvertTo _
    (ByVal context As ITypeDescriptorContext, _
    ByVal destinationType As Type) _
  As Boolean

      If destinationType Is GetType(InstanceDescriptor) Then
        Return True
      ElseIf destinationType Is GetType(String) Then
        Return True
      End If
      Return MyBase.CanConvertTo(context, destinationType)

  End Function


  Public Overloads Overrides Function ConvertTo _
    (ByVal context As ITypeDescriptorContext, _
    ByVal culture As System.Globalization.CultureInfo, _
    ByVal value As Object, _
    ByVal destinationType As Type) _
  As Object

      If destinationType Is GetType(InstanceDescriptor) Then
        Dim ci As ConstructorInfo = GetType(Appearance).GetConstructor(New Type() {})
        Dim a As Appearance = CType(value, Appearance)
        Return New InstanceDescriptor(ci, New Object() {})
      ElseIf destinationType Is GetType(String) Then
        Return "Appearance"
      End If
      Return MyBase.ConvertTo(context, culture, value, destinationType)

  End Function

End Class

Joe Paradise
Tuesday, June 07, 2005

Found a solution (if anyone's interested).  I thought I had to make a custom TypeConverter that inherited ExpandableObjectConverter.  What I should have done is just used ExpandableObjectConverter in the TypeConverter attribute for Appearance.

Joe Paradise
Wednesday, June 08, 2005

*  Recent Topics

*  Fog Creek Home