Default property values with custom TypeConverters

G

Guest

I'm attempting to create TypeConverters for the PointF, SizeF, and RectangleF drawing structures. Everything seems to work as expected except when I use a PropertyGrid control to expose properties that utilize the converters. When I do this the text for the properites in the PropertyGrid is always bold, even when the text equals the property's default value. Can somebody please tell me how to support default values when using custom TypeConverts. Here is some sample code:


Public Class Form1
Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

Public Sub New()
MyBase.New()

'This call is required by the Windows Form Designer.
InitializeComponent()

'Add any initialization after the InitializeComponent() call
Call Me.Initialize()
End Sub

'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub

'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(6, 15)
Me.ClientSize = New System.Drawing.Size(292, 258)
Me.Name = "Form1"
Me.Text = "Form1"

End Sub

#End Region

Protected _PropertyGrid As New Windows.Forms.PropertyGrid
Protected _TestClass As New Class1.TestClass

Private Sub Initialize()
Me._PropertyGrid.Dock = DockStyle.Fill
Me._PropertyGrid.SelectedObject = Me._TestClass

Me.Controls.Add(Me._PropertyGrid)
End Sub

End Class

Public Class Class1

#Region " TestClass "

Public Class TestClass

Protected _MyPointF As Drawing.PointF
Protected _MyPoint As Drawing.Point

Public Event MyPointFChanged As System.EventHandler
Public Event MyPointChanged As System.EventHandler

Protected Overridable Overloads Sub OnMyPointFChanged(ByVal e As System.EventArgs)
RaiseEvent MyPointFChanged(Me, e)
End Sub
Protected Overloads Sub OnMyPointFChanged()
Call Me.OnMyPointFChanged(System.EventArgs.Empty)
End Sub

Protected Overridable Overloads Sub OnMyPointChanged(ByVal e As System.EventArgs)
RaiseEvent MyPointChanged(Me, e)
End Sub
Protected Overloads Sub OnMyPointChanged()
Call Me.OnMyPointChanged(System.EventArgs.Empty)
End Sub

<System.ComponentModel.RefreshProperties(System.ComponentModel.RefreshProperties.All), _
System.ComponentModel.Bindable(True), _
System.ComponentModel.DefaultValue(GetType(Drawing.PointF), "0, 0"), _
System.ComponentModel.Browsable(True), _
System.ComponentModel.TypeConverter(GetType(PointFConverter))> _
Public Property MyPointF() As Drawing.PointF
Get
Return Me._MyPointF
End Get
Set(ByVal value As Drawing.PointF)
If (Drawing.PointF.op_Equality(Me._MyPointF, value)) Then Exit Property

Me._MyPointF = value
Call Me.OnMyPointFChanged()
End Set
End Property

<System.ComponentModel.RefreshProperties(System.ComponentModel.RefreshProperties.All), _
System.ComponentModel.Bindable(True), _
System.ComponentModel.DefaultValue(GetType(Drawing.Point), "0, 0"), _
System.ComponentModel.Browsable(True)> _
Public Property MyPoint() As Drawing.Point
Get
Return Me._MyPoint
End Get
Set(ByVal value As Drawing.Point)
If (Drawing.Point.op_Equality(Me._MyPoint, value)) Then Exit Property

Me._MyPoint = value
Call Me.OnMyPointChanged()
End Set
End Property

Public Sub New()
Call MyBase.New()
End Sub

End Class

#End Region

#Region " PointFConverter "

Public Class PointFConverter
Inherits System.ComponentModel.ExpandableObjectConverter

Public Const gcFormatString As String = ""


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

'Return True if destinationType is a class that is supported by this Converter.
If (destinationType Is GetType(Drawing.PointF)) OrElse _
(destinationType Is GetType(System.ComponentModel.Design.Serialization.InstanceDescriptor)) Then

Return True
End If

'If we get here then we must use a method from MyBase since we encountered a type that is not supported by this class.
Return MyBase.CanConvertFrom(context, destinationType)
End Function


Public Overloads Overrides Function CanConvertFrom( _
ByVal context As System.ComponentModel.ITypeDescriptorContext, _
ByVal sourceType As System.Type) As Boolean

'Return True if sourceType is a string.
If (sourceType Is GetType(String)) Then Return True

'If we get here then we must use a method from MyBase since we encountered a type that is not supported by this class.
Return MyBase.CanConvertFrom(context, sourceType)
End Function


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

If ((TypeOf value Is Drawing.PointF) AndAlso (destinationType Is GetType(System.String))) Then
'Convert value to the appropriate type.
Dim point As Drawing.PointF = DirectCast(value, Drawing.PointF)

'Convert value to a string.
With point
Dim propertyValues() As String = {.X.ToString(gcFormatString), .Y.ToString(gcFormatString)}

Return JoinConverterDestinationStringArray(propertyValues)
End With 'From point

ElseIf ((TypeOf value Is Drawing.PointF) AndAlso (destinationType Is GetType(System.ComponentModel.Design.Serialization.InstanceDescriptor))) Then
MessageBox.Show("Not Supported!")
End If

'If we get here then we must use a method from MyBase since we encountered a type that is not supported by this method.
Return MyBase.ConvertTo(context, culture, value, destinationType)
End Function


Public Overloads Overrides Function ConvertFrom( _
ByVal context As System.ComponentModel.ITypeDescriptorContext, _
ByVal culture As System.Globalization.CultureInfo, _
ByVal value As Object) As Object

If (TypeOf value Is String) Then
Try
'Split value into its individual values.
Dim propertyValues() As String = SplitConverterSourceString(CStr(value))

'Convert the values.
Dim x As Single = CSng(propertyValues(0))
Dim y As Single = CSng(propertyValues(1))

'Return the object that corresponds to value.
Return New Drawing.PointF(x, y)

Catch e As Exception
MessageBox.Show(e.ToString)
End Try
End If

'If we get here then we must use a method from MyBase since we encountered a type that is not supported by this method.
Return MyBase.ConvertFrom(context, culture, value)
End Function


Public Shared Function SplitConverterSourceString(ByVal sourceString As String) As String()
Dim i As Integer
Dim splitString() As String 'Return value.

'Validate sourceString
If (sourceString = "") Then Return Nothing

'Split sourceString into its individual PropertyValues
splitString = Microsoft.VisualBasic.Split(sourceString, ",")

'Make sure that splitString has at least one value
If (splitString Is Nothing) Then Return Nothing

'Trim each of the members in splitString
For i = splitString.GetLowerBound(0) To splitString.GetUpperBound(0)
splitString(i) = Microsoft.VisualBasic.Trim(splitString(i))
Next i

Return splitString
End Function


Public Shared Function JoinConverterDestinationStringArray(ByVal destinationString() As String) As String
'Validate destinationString
If (destinationString Is Nothing) Then Return ""

Return Microsoft.VisualBasic.Join(destinationString, ", ")
End Function

End Class

#End Region

End Class


Thanks for any help!
Lance
 
J

Jeffrey Tan[MSFT]

Hi zippy,

I have reviewed your issue, I will spend some time to do some research on
it. I will reply to you ASAP.

Thanks for your understanding.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi zippy,

Sorry for letting you wait for so long time.

I think you want to apply the DefaultValueAttribute to some property, such
as MyPointF. But it does not work for you.

Actually, for complex type property, you should use another approach to
complete the DefaultValueAttribute function. You write a method for your
class like:
private bool ShouldSerialize[Your property name]()

For MyPointF, you should use
private bool ShouldSerializeMyPointF()

The VS.net will dynamically invoke your method for that property. In that
method, you may determine if the MyPointF's value equals a default value,
then return false to tell the VS.net IDE to not serialize that
property.(Not being bold font)

I have writen a sample in C#, like this(If you need help to convert it to
VB.net, please tell me, I will help you):

private Person _test=new Person();

public Person Test
{
get
{
return _test;
}
set
{
_test=value;
}
}

private bool ShouldSerializeTest()
{
if(this.Test.Age==22)
{
if(this.Test.FirstName=="Jeffrey")
{
if(this.Test.LastName=="Tan")
{
return false;
}
}
}

return true;
}

[TypeConverter(typeof(PersonConverter))]
public class Person
{
private string firstName = "";
private string lastName = "";
private int age = 0;

public Person()
{
}

public Person(string fn, string ln, int age)
{
this.firstName= fn;
this.lastName= ln;
this.age= age;
}

[DefaultValue(22)]
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}

[DefaultValue("Jeffrey")]
public string FirstName
{
get
{
return firstName;
}
set
{
this.firstName = value;
}
}

[DefaultValue("Tan")]
public string LastName
{
get
{
return lastName;
}
set
{
this.lastName = value;
}
}
}

internal class PersonConverter : ExpandableObjectConverter
{


public override bool CanConvertFrom(
ITypeDescriptorContext context, Type t)
{

if (t == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, t);
}

public override object ConvertFrom(
ITypeDescriptorContext context,
System.Globalization.CultureInfo info,
object value)
{

if (value is string)
{
try
{
string s = (string) value;
// parse the format "Last, First (Age)"
//
int comma = s.IndexOf(',');
if (comma != -1)
{
// now that we have the comma, get
// the last name.
string last = s.Substring(0, comma);
int paren = s.LastIndexOf('(');
if (paren != -1 &&
s.LastIndexOf(')') == s.Length - 1)
{
// pick up the first name
string first =
s.Substring(comma + 1,
paren - comma - 1);
// get the age
int age = Int32.Parse(
s.Substring(paren + 1,
s.Length - paren - 2));
Person p = new Person();
p.Age = age;
p.LastName = last.Trim();
p.FirstName = first.Trim();
return p;
}
}
}
catch {}
// if we got this far, complain that we
// couldn't parse the string
//
throw new ArgumentException(
"Can not convert '" + (string)value +
"' to type Person");

}
return base.ConvertFrom(context, info, value);
}

public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture,
object value,
Type destType)
{
if (destType == typeof(string) && value is Person)
{
Person p = (Person)value;
// simply build the string as "Last, First (Age)"
return p.LastName + "," +
p.FirstName + ","+
p.Age.ToString();
}
return base.ConvertTo(context, culture, value, destType);
}
}

If you use Age 22, FistName "Jeffrey", LastName "Tan", then the font will
not be bold.

Please apply my suggestion above and let me know if it helps resolve your
problem.

Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi zippy,

Does the my reply make sense to you? Is your problem resolved?

Please feel free to feedback, I will help you, thanks.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
G

Guest

Sorry, I didn't realize that you responded. Anyway, your example does what I wanted to do. Thanks!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top