Question

Why in the world does the following property appear readonly in the PropertyGrid?

Public Property Location() As PointF
    Get
        Return New PointF(mLeft, mTop)
    End Get
    Set(ByVal value As PointF)
        mLeft = value.X
        mTop = value.Y
    End Set
End Property

while the following property of the same object appears just fine (read/write):

Public Property Size() As SizeF
    Get
        Return New SizeF(mWidth, mHeight)
    End Get
    Set(ByVal value As SizeF)
        mWidth = value.Width
        mHeight = value.Height
    End Set
End Property

In fact the PropertyGrid displays the ToString() version of my first property, i.e. the value is like {X=103, Y=235} for Location.

Was it helpful?

Solution

Because SizeF has a default TypeConverter defined:

[Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true), TypeConverter(typeof(SizeFConverter))]
public struct SizeF
{
   ...
}

While PointF has not:

[Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true)]
public struct PointF
{
    ....
}

OTHER TIPS

For anyone else banging their head against the wall, here the PointFConverter class:

Imports System.ComponentModel

Public Class PointFConverter
    Inherits ExpandableObjectConverter

    Public Overrides Function CanConvertFrom(context As ITypeDescriptorContext, sourceType As Type) As Boolean
        If sourceType = GetType(String) Then
            Return True
        Else
            Return MyBase.CanConvertFrom(context, sourceType)
        End If
    End Function

    Public Overrides Function ConvertFrom(context As ITypeDescriptorContext, culture As System.Globalization.CultureInfo, value As Object) As Object
        If TypeOf value Is String Then
            Try
                Dim s As String = DirectCast(value, String)
                Dim converterParts As String() = s.Split(","c)
                Dim x As Single = 0.0F
                Dim y As Single = 0.0F
                If converterParts.Length > 1 Then
                    x = Single.Parse(converterParts(0).Trim())
                    y = Single.Parse(converterParts(1).Trim())
                ElseIf converterParts.Length = 1 Then
                    x = Single.Parse(converterParts(0).Trim())
                End If
                Return New PointF(x, y)
            Catch
                Throw New ArgumentException("Cannot convert [" + value.ToString() + "] to pointF")
            End Try
        End If
        Return MyBase.ConvertFrom(context, culture, value)
    End Function

    Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As System.Globalization.CultureInfo, value As Object, destinationType As Type) As Object
        If destinationType = GetType(String) Then
            If value.[GetType]() = GetType(PointF) Then
                Dim pt As PointF = DirectCast(value, PointF)
                Return String.Format("{0}, {1}", pt.X, pt.Y)
            End If
        End If

        Return MyBase.ConvertTo(context, culture, value, destinationType)
    End Function
End Class

Simply apply it on your property like this:

<TypeConverter(GetType(PointFConverter))> _
Public Property Location() As PointF
    Get
        Return New PointF(mLeft, mTop)
    End Get
    Set(ByVal value As PointF)
        mLeft = value.X
        mTop = value.Y
    End Set
End Property
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top