WinForms UserControl如何根据LookupType属性条件显示对应相关属性?
结论
不能动态修改属性的访问修饰符:访问修饰符是编译阶段就确定的元数据,运行时无法变更。但你可以通过.NET组件模型提供的能力,实现「仅在IntelliSense和属性窗口中暴露当前LookupType匹配属性」的需求,和你要的效果完全一致。
通用解决方案:实现ICustomTypeDescriptor接口
该接口是.NET为动态类型元数据场景提供的官方支持,设计器、IntelliSense都会优先读取该接口返回的属性列表,你只需要在对应方法中根据当前LookupType过滤属性即可,完整实现示例如下:
public enum LookupType { None, Vendor, ShipMeth } public partial class LookupControl : UserControl, ICustomTypeDescriptor { // 你原有的查询类型控制属性 public LookupType LookupType { get; set; } // 各类型专属属性 public string Vendor_RemitToAddr { get; set; } public int ShipMeth_ShipMethID { get; set; } // 核心方法:过滤要对外暴露的属性 public PropertyDescriptorCollection GetProperties(Attribute[] attributes) { // 获取控件所有原生属性 var allProps = TypeDescriptor.GetProperties(this, attributes, true); var filteredProps = new List<PropertyDescriptor>(); foreach (PropertyDescriptor prop in allProps) { // 保留通用属性:LookupType本身、BackColor/Width等基础控件属性 if (prop.Name == nameof(LookupType) || !prop.Name.Contains('_')) { filteredProps.Add(prop); continue; } // 专属属性仅保留和当前LookupType匹配的 var propTypePrefix = prop.Name.Split('_')[0]; if (LookupType.ToString() == propTypePrefix) { filteredProps.Add(prop); } } return new PropertyDescriptorCollection(filteredProps.ToArray()); } // 剩余ICustomTypeDescriptor接口方法直接转发默认实现即可 public AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true); public string GetClassName() => TypeDescriptor.GetClassName(this, true); public string GetComponentName() => TypeDescriptor.GetComponentName(this, true); public TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, true); public EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, true); public PropertyDescriptor GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true); public object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, true); public EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, true); public EventDescriptorCollection GetEvents(Attribute[] attributes) => TypeDescriptor.GetEvents(this, attributes, true); public PropertyDescriptorCollection GetProperties() => GetProperties(null); public object GetPropertyOwner(PropertyDescriptor pd) => this; }
补充优化
如果你需要避免开发者在代码中误用不匹配的属性,可以在专属属性的get/set逻辑中增加校验,示例如下:
private string _vendor_RemitToAddr; public string Vendor_RemitToAddr { get { if (LookupType != LookupType.Vendor) throw new InvalidOperationException($"仅当LookupType为{nameof(LookupType.Vendor)}时可访问该属性"); return _vendor_RemitToAddr; } set { if (LookupType != LookupType.Vendor) throw new InvalidOperationException($"仅当LookupType为{nameof(LookupType.Vendor)}时可设置该属性"); _vendor_RemitToAddr = value; } }
该方案同时兼容WinForm、WPF的设计器,不需要额外适配。
内容的提问来源于stack exchange,提问作者Lisa
相关产品推荐
相关产品推荐

