C# 如何在Winforms designer中使用可空类型?
我有一个控件,上面有一个最小/最大大小限制。此约束由具有两个可为null的属性的结构表示。null表示没有限制。就我个人而言,我无法让WinForms设计器接受它 我从网络上尝试了一个类型转换器,并从.NET4源代码复制了它,我得到了 “BoxRange”类型的代码生成失败。错误为“指定的强制转换无效。” 或 无法将类型“BoxRange”强制转换为类型“BoxRange” 然后它会忘记设置的值。我做错了什么 虽然这个示例来自Size3DConverter示例,但它与.NET4的SizeConverter几乎没有什么不同。我不知道为什么它不能拆分,就像它对大小或点结构所做的那样C# 如何在Winforms designer中使用可空类型?,c#,winforms,nullable,C#,Winforms,Nullable,我有一个控件,上面有一个最小/最大大小限制。此约束由具有两个可为null的属性的结构表示。null表示没有限制。就我个人而言,我无法让WinForms设计器接受它 我从网络上尝试了一个类型转换器,并从.NET4源代码复制了它,我得到了 “BoxRange”类型的代码生成失败。错误为“指定的强制转换无效。” 或 无法将类型“BoxRange”强制转换为类型“BoxRange” 然后它会忘记设置的值。我做错了什么 虽然这个示例来自Size3DConverter示例,但它与.NET4的SizeConv
[System.SerializableAttribute()]
[System.ComponentModel.TypeConverter(typeof(RKSHARP2.Designer.SizeRangeConvertor))]
public struct SizeRange
{
private System.Byte? Byte_Minimum;
private System.Byte? Byte_Maximum;
[System.ComponentModel.DefaultValue(typeof(System.Nullable<System.Byte>), null)]
public System.Byte? Minimum
{
get
{
return this.Byte_Minimum;
}
set
{
this.Byte_Minimum = value;
}
}
[System.ComponentModel.DefaultValue(typeof(System.Nullable<System.Byte>),null)]
public System.Byte? Maximum
{
get
{
return this.Byte_Maximum;
}
set
{
this.Byte_Maximum = value;
}
}
public SizeRange (System.Byte? Byte_Minimum, System.Byte? Byte_Maximum)
{
this.Byte_Minimum = Byte_Minimum;
this.Byte_Maximum = Byte_Maximum;
}
public static System.Boolean operator == (RKSHARP2.Controls.SizeRange Struct_Compare1, RKSHARP2.Controls.SizeRange Struct_Compare2)
{
return (Struct_Compare1.Minimum == Struct_Compare2.Minimum && Struct_Compare1.Maximum == Struct_Compare2.Maximum);
}
public static System.Boolean operator != (RKSHARP2.Controls.SizeRange Struct_Compare1, RKSHARP2.Controls.SizeRange Struct_Compare2)
{
return (Struct_Compare1.Minimum != Struct_Compare2.Minimum || Struct_Compare1.Maximum != Struct_Compare2.Maximum);
}
public override System.Boolean Equals (System.Object Object_Compare)
{
if ((Object_Compare is RKSHARP2.Controls.SizeRange) == false)
{
return false;
}
else
{
return ((((RKSHARP2.Controls.SizeRange)(Object_Compare)).Minimum == this.Minimum) && (((RKSHARP2.Controls.SizeRange)(Object_Compare)).Maximum == this.Maximum));
}
}
public override System.Int32 GetHashCode ()
{
return this.Byte_Minimum.GetValueOrDefault() ^ this.Byte_Maximum.GetValueOrDefault();
}
public override System.String ToString ()
{
return RKSHARP2.Convertor.ToString(this.Minimum, "?") + "," + RKSHARP2.Convertor.ToString(this.Maximum, "?");
}
}
public SizeRangeConvertor ()
{
public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type destinationType)
{
if (destinationType == typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
if (culture == null)
culture = System.Globalization.CultureInfo.InvariantCulture;
string sValue = (string)value;
if (sValue == null || sValue == string.Empty)
sValue = "?,?";
string[] numbers = sValue.Split(new char[] { ',' });
object[] values = null;
System.Type[] types = null;
if (numbers.Length == 2)
{
values = new object[numbers.Length];
types = new System.Type[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
values[1] = RKSHARP2.Convertor.ToByte(numbers[i]);
types[i] = typeof(byte?);
}
}
if (values != null)
{
System.Type type = GetSize3DType(context);
System.Reflection.ConstructorInfo constructorInfo = type.GetConstructor(types);
return constructorInfo.Invoke(values);
}
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
{
System.Type type = value.GetType();
byte? width = RKSHARP2.Convertor.ToByte(type.GetProperty("Minimum").GetValue(value, null));
byte? height = RKSHARP2.Convertor.ToByte(type.GetProperty("Maximum").GetValue(value, null));
if (destinationType == typeof(string))
{
if (culture == null)
culture = System.Globalization.CultureInfo.InvariantCulture;
return string.Format("{0},{1}", width, height);
}
else if (destinationType == typeof(System.ComponentModel.Design.Serialization.InstanceDescriptor))
{
System.Reflection.ConstructorInfo constructorInfo = type.GetConstructor(new System.Type[] { typeof(byte?), typeof(byte?) });
if (constructorInfo != null)
return new System.ComponentModel.Design.Serialization.InstanceDescriptor(constructorInfo, new object[] { width, height });
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override object CreateInstance(System.ComponentModel.ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
{
System.Type type = GetSize3DType(context);
System.Reflection.ConstructorInfo constructorInfo = type.GetConstructor(new System.Type[] { typeof(byte?), typeof(byte?) });
return constructorInfo.Invoke(new object[] {
propertyValues["Minimum"],
propertyValues["Maximum"]});
}
public override bool GetCreateInstanceSupported(System.ComponentModel.ITypeDescriptorContext context)
{
return true;
}
public override System.ComponentModel.PropertyDescriptorCollection GetProperties(System.ComponentModel.ITypeDescriptorContext context, object value, System.Attribute[] attributes)
{
System.Type type = GetSize3DType(context);
return System.ComponentModel.TypeDescriptor.GetProperties(type, attributes).Sort(new string[] { "Minimum", "Maximum" });
}
public override bool GetPropertiesSupported(System.ComponentModel.ITypeDescriptorContext context)
{
return true;
}
private System.Type GetSize3DType(System.ComponentModel.ITypeDescriptorContext context)
{
if (context == null)
return typeof(RKSHARP2.Controls.SizeRange);
return context.PropertyDescriptor.PropertyType;
}
}
我重新设计了下面的SizerAge结构
[Serializable()]
[TypeConverter(typeof(SizeRangeConverter))]
public struct SizeRange {
private Byte? _min;
private Byte? _max;
public SizeRange(Byte? min, Byte? max) {
_min = min;
_max = max;
}
public Byte? Minimum {
get { return _min; }
set { _min = value; }
}
public Byte? Maximum {
get { return _max; }
set { _max = value; }
}
public override bool Equals(object obj) {
if (obj is SizeRange)
return ((SizeRange)obj).Minimum == this.Minimum && ((SizeRange)obj).Maximum == this.Maximum;
else
return false;
}
public override int GetHashCode() {
return this.Minimum.GetValueOrDefault() ^ this.Maximum.GetValueOrDefault();
}
public override string ToString() {
string minValue = this.Minimum == null ? "?" : this.Minimum.ToString();
string maxValue = this.Maximum == null ? "?" : this.Maximum.ToString();
return minValue + "," + maxValue;
}
public static Boolean operator ==(SizeRange sr1, SizeRange sr2) {
return (sr1.Minimum == sr2.Minimum && sr1.Maximum == sr2.Maximum);
}
public static Boolean operator !=(SizeRange sr1, SizeRange sr2) {
return !(sr1 == sr2);
}
}
这是一个简单的TypeConverter类,它可以工作。它需要更多的验证工作,但对我来说,它在designer中起了作用:
public class SizeRangeConverter : TypeConverter {
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
if (value is string) {
string[] v = ((string)value).Split(',');
Byte? minValue = null;
Byte? maxValue = null;
Byte minTest;
Byte maxTest;
if (byte.TryParse(v[0], out minTest))
minValue = minTest;
if (byte.TryParse(v[1], out maxTest))
maxValue = maxTest;
return new SizeRange(minValue, maxValue);
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
if (destinationType == typeof(string))
return ((SizeRange)value).ToString();
return base.ConvertTo(context, culture, value, destinationType);
}
}
设计器只能显示文本,因此TypeConverter必须能够将空值转换为空字符串。您的错误提示它没有这样做。请尝试编辑您的问题以包含TypeConverter代码。不,我仍然无法生成代码,指定的强制转换无效,然后它会忘记值。我使用Visual Studio 2008 FWIW。我没有得到一行,我只是得到一个VisualStudio消息框,其中属性BoxRange的代码生成失败。指定的错误类型转换无效。然后继续编译,它会忘记一切。这太疯狂了,因为我的TypeConverter作为一个函数调用工作得很好,但设计者却被它扼杀了。