为附加属性添加TypeConverter后,VS设计器新建按钮消失问题排查
问题
定义了一个WPF附加属性UiData,类型为自定义类UiControlData。原本在Visual Studio设计器属性窗口中,可通过“New”按钮创建该对象并编辑子属性。为了根据UIElement类型控制子属性显示(如隐藏特定属性),创建了继承自ExpandableObjectConverter的MyComplexObjectConverter并添加到UiControlData类上,但此时设计器中的“New”按钮消失。
编写的TypeConverter代码如下:
public class MyComplexObjectConverter : ExpandableObjectConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { if (sourceType == typeof(string) || sourceType == typeof(UiControlData)) { return true; } return base.CanConvertFrom(context, sourceType); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value == null) { return null; } if (value is string) { return new UiControlData(); } if (value is UiControlData) { return value; } return base.ConvertFrom(context, culture, value); } public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { PropertyDescriptorCollection originalProperties = base.GetProperties(context, value, attributes); return originalProperties; } }
已尝试的操作:
- 附加调试器到WpfSurface调试,发现转换函数未被调用
- 在附加属性的Get方法上添加
[System.ComponentModel.TypeConverter(typeof(MyComplexObjectConverter))]属性,问题依旧
需要排查或解决方法。
排查与解决方法
- 确认TypeConverter的标记位置:确保
[TypeConverter(typeof(MyComplexObjectConverter))]直接标记在UiControlData类上,设计器优先识别类级别的转换器标记,仅标记在附加属性Get方法上可能不生效。 - 重写CanConvertTo方法:设计器创建对象时依赖
CanConvertTo的支持,当前转换器未实现该方法,添加以下代码:public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { if (destinationType == typeof(string) || destinationType == typeof(InstanceDescriptor)) { return true; } return base.CanConvertTo(context, destinationType); }InstanceDescriptor是设计器生成对象实例的关键类型,返回true可让设计器识别创建实例的逻辑。 - 完善GetProperties的上下文处理:当前方法仅返回原始属性,若要根据
UIElement类型过滤属性,需从context.Instance获取目标元素后再处理,示例:
若上下文处理不当,设计器可能无法识别属性结构,导致“New”按钮消失。public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { var originalProperties = base.GetProperties(context, value, attributes); if (context.Instance is UIElement element) { var filteredProperties = new List<PropertyDescriptor>(); foreach (PropertyDescriptor prop in originalProperties) { // 示例:Button类型隐藏特定属性 if (element is Button && prop.Name == "NonButtonProperty") { continue; } filteredProperties.Add(prop); } return new PropertyDescriptorCollection(filteredProperties.ToArray()); } return originalProperties; } - 清理设计器缓存并重启VS:Visual Studio设计器可能缓存旧元数据,尝试:
- 清理项目的
bin和obj目录后重新编译 - 关闭所有VS窗口,重启后重新打开项目
- 通过
Tools > Options > XAML Designer > Reset Designer重置设计器
- 清理项目的
- 检查UiControlData的构造函数:确保
UiControlData有无参构造函数,设计器创建对象依赖无参构造,若只有带参构造,“New”按钮会消失。 - 通过日志调试转换器方法:附加调试器到WpfSurface可能无法命中断点,可在
CanConvertFrom、CanConvertTo、GetProperties方法中添加本地文件日志输出,确认这些方法是否被设计器调用,定位未触发的原因。
内容的提问来源于stack exchange,提问作者Alex R
相关产品推荐
相关产品推荐

