Problem with type converter

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I have written a component with a property IPAdrress of type
System.Net.IPAddress. To ease the configuration of the component at design
time, I have written a type converter for the type System.Net.IPAddress. The
type System.Net.IPAddress, as you know, is provided by Microsoft and I have
no choice but to apply the type converter on the IPAddress property of the
component itself (instead of the type System.Net.IPAddress). All normal
features of a type converter are working perfectly but I just couldn't get
VS.NET 2003 to produce constructor-based property initialization code for the
IPAddress property of the component as follow

this.myComponent.IPAddress = new System.Net.IPAddress(0);

instead of

this.myComponent.IPAddress.Address = 0;
or
this.myComponent.IPAddress =
((System.Net.IPAddress)(resources.GetObject("myComponent.IPAddress")));

This wouldn't have happened if I were able to apply the type converter on
the type System.Net.IPAddress itself. How do I get around this? Thanks.

Code of the component (extract) and the type converter follow:

// MyComponent.cs
public class MyComponent : System.ComponentModel.Component
{
// ...
[TypeConverter(typeof(IPAddressConverter))]
public IPAddress IPAddress
{
get
{
return ipAddr;
}
set
{
if(value == null)
throw new ArgumentNullException("IPAddress");
ipAddr = value;
}
}
// ...
}

// IPAddressConverter.cs
using System;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Net;
using System.Net.Sockets;
using System.Reflection;

namespace Util.Net
{
public class IPAddressConverter : System.ComponentModel.TypeConverter
{
private const string ANY = "Any";
private const string LOOPBACK = "Loopback";
private const string ANYIPADDRESS = "0.0.0.0";
private const string LOOPBACKIPADDRESS = "127.0.0.1";

public IPAddressConverter()
{
}

public override bool
CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context,
System.Type sourceType)
{
if(sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}

public override object
ConvertFrom(System.ComponentModel.ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value)
{
if(value is string)
{
if((string)value == ANY)
value = ANYIPADDRESS;
else if((string)value == LOOPBACK)
value = LOOPBACKIPADDRESS;
return IPAddress.Parse((string)value);
}
return base.ConvertFrom(context, culture, value);
}

public override bool
CanConvertTo(System.ComponentModel.ITypeDescriptorContext context,
System.Type destinationType)
{
if(destinationType == typeof(InstanceDescriptor))
return true;
return base.CanConvertTo(context, destinationType);
}

public override object
ConvertTo(System.ComponentModel.ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, System.Type
destinationType)
{
if(destinationType == typeof(string) && value is IPAddress)
{
if(value.Equals(IPAddress.Any))
return ANY;
if(value.Equals(IPAddress.Loopback))
return LOOPBACK;
return value.ToString();
}
if(destinationType == typeof(InstanceDescriptor) && value is IPAddress &&
((IPAddress)value).AddressFamily == AddressFamily.InterNetwork)
{
ConstructorInfo constructorInfo = typeof(IPAddress).GetConstructor(
new Type[]{typeof(long)});
if(constructorInfo != null)
{
// return new InstanceDescriptor(constructorInfo, new long[]{
// ((IPAddress)value).Address});
byte[] addressBytes = ((IPAddress)value).GetAddressBytes();
long address = addressBytes[0] | (addressBytes[1] << 8) |
(addressBytes[2] << 16) | (addressBytes[3] << 24);
return new InstanceDescriptor(constructorInfo, new
long[]{address});
}
}
return base.ConvertTo(context, culture, value, destinationType);
}

public override bool
GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext
context)
{
return true;
}

public override System.ComponentModel.TypeConverter.StandardValuesCollection
GetStandardValues(System.ComponentModel.ITypeDescriptorContext context)
{
// IPAddress[] specialIPAddresses = {
// new IPAddress(IPAddress.Any.Address),
// new IPAddress(IPAddress.Loopback.Address)};
IPAddress[] specialIPAddresses = {
new IPAddress(0),
new IPAddress(0x0100007F)};
return new StandardValuesCollection(specialIPAddresses);
}
}
}
 
Hi,

First of all, I would like to confirm my understanding of your issue. From
your description, I'm not quite sure what you need to do. Do you mean that
a constructor that can convert as the type converter does, to initialize
the IPAddress? If there is any misunderstanding, please feel free to let me
know.

If so, I think we cannot do with the IPAddress class, since it doesn't have
a constructor that does so. I think you can try to overload the constructor
of IPAddressConverter to achieve this.

Please correct me if my understanding is wrong. Thanks!

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."
 
Hi Kevin,

I want my component to be able to generate a constructor-based
initialization for its IPAddress property. For example, if I set the
IPAddress property to be "127.0.0.1", it should generate in the
InitializeComponent() method of its container the following code

this.myComponent.IPAddress = new System.Net.IPAddress(16777343);
// 16777343 is the equivalent of 127.0.0.1

rather than

this.myComponent.IPAddress =
((System.Net.IPAddress)(resources.GetObject("myComponent.IPAddress")));

The System.Net.IPAddress type does have a constructor that takes a long
address as parameter. I've written the IPAddressConverter type to accomplish
this. The code is found in the overriden ConvertTo method below but
unfortunately it does not work as expected. Kindly advise. Thanks.

public override object
ConvertTo(System.ComponentModel.ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, System.Type
destinationType)
{
if(destinationType == typeof(string) && value is IPAddress)
{
if(value.Equals(IPAddress.Any))
return ANY;
if(value.Equals(IPAddress.Loopback))
return LOOPBACK;
return value.ToString();
}
if(destinationType == typeof(InstanceDescriptor) && value is IPAddress &&
((IPAddress)value).AddressFamily == AddressFamily.InterNetwork)
{
ConstructorInfo constructorInfo = typeof(IPAddress).GetConstructor(
new Type[]{typeof(long)});
if(constructorInfo != null)
{
// return new InstanceDescriptor(constructorInfo, new long[]{
// ((IPAddress)value).Address});
byte[] addressBytes = ((IPAddress)value).GetAddressBytes();
long address = addressBytes[0] | (addressBytes[1] << 8) |
(addressBytes[2] << 16) | (addressBytes[3] << 24);
return new InstanceDescriptor(constructorInfo, new
long[]{address});
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
 
Hi,

For this issue, we have reproduce out the problem, it seems that IPAddress
always use binary serialization for code generator. We will spend some more
time on it. We will update 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.
 
Hi,

My investigation shows that if I were able to apply the TypeConverter
attribute on the type itself (in my case the System.Net.IPAddress type)
rather than on the property of this type of the component (in my case the
MyComponent.IPAddress property), VS .NET would produce the correct
initialization code. This is hypothetical of course since the
System.Net.IPAddress type is provided by Microsoft. Thanks.
 
Hi,

I debugged the sample and can confirm that serialization indeed doesn't
seem to pick up type converters attached to properties. In this case, you
have a type converter attached to a property of type IPAddress and not the
IPAddress class itself, so it is by design that serialization doesn't find
it.

Kevin Yu
=======
"This posting is provided "AS IS" with no warranties, and confers no
rights."
 
Back
Top