WinForms UserControl 属性的条件显示?
Conditional display of properties for a WinForms UserControl?
我有一个执行查找的 UserControl。它执行的查找类型取决于名为 LookupType 的 属性。 UserControl 中有与每个 LookupType 相关的属性。因此,例如,LookupType = Vendor 具有 Vendor_RemitToAddr 等属性,而 LookupType = ShipMeth 具有 ShipMeth_ShipMethID.
等属性
Intellisense 和 Properties window 显示了所有这些,这是有道理的。但我希望能够让 UserControl 仅公开与所选 LookupType 相关的属性。
有什么方法可以根据 LookupType 更改属性的访问修饰符 属性?
注意:这与其说是功能问题,不如说是用户体验问题。查找工作正常。但是在开发的时候看起来乱七八糟,开发者-用户可以误设置错误属性。
这是一个只有 3 个属性的 UserControl 的简化示例:LookupType
、RemitToAddr
(仅对 LookupType.Vendor 有效)、ShipMethID
(仅对 LookupType.ShipMeth).首先,LookupControl
:
public enum LookupType
{
Vendor,
ShipMeth
}
[TypeConverter(typeof(LookupControlConverter))]
public partial class LookupControl : UserControl
{
private LookupType lookupType;
public LookupControl()
{
InitializeComponent();
}
[RefreshProperties(RefreshProperties.All)]
[Browsable(true)]
public LookupType LookupType
{
get => lookupType;
set
{
lookupType = value;
// Clear out unwanted property values
switch (value)
{
case LookupType.Vendor:
ShipMethID = null;
break;
case LookupType.ShipMeth:
RemitToAddr = null;
break;
}
}
}
[Browsable(true)]
public string RemitToAddr { get; set; }
[Browsable(true)]
public string ShipMethID { get; set; }
}
LookupControl 在 LookupType
属性 setter 中包含一些逻辑,用于清除对当前 LookupType 没有意义的属性值。这可以确保您的控件不会有不一致的 属性 值。
对于 Windows Forms Designer 中的 PropertyGrid,我实现了 TypeConverter
:
internal sealed class LookupControlConverter : TypeConverter
{
private readonly PropertyDescriptorCollection allProps = TypeDescriptor.GetProperties(typeof(LookupControl), new[] { BrowsableAttribute.Yes });
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
if (context?.Instance is LookupControl)
return true;
return base.GetPropertiesSupported(context);
}
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
if (context.Instance is LookupControl control)
{
var propList = allProps.Cast<PropertyDescriptor>().ToList();
// Remove the unwanted property descriptors based on the current value of LookupType
switch (control.LookupType)
{
case LookupType.Vendor:
propList.Remove(allProps[nameof(LookupControl.ShipMethID)]);
break;
case LookupType.ShipMeth:
propList.Remove(allProps[nameof(LookupControl.RemitToAddr)]);
break;
}
return new PropertyDescriptorCollection(propList.ToArray(), true);
}
return allProps;
}
}
注意:要使LookupControlConverter
生效,需要在用户控件上应用[TypeConverter(typeof(LookupControlConverter))]
属性,在属性上应用[RefreshProperties(RefreshProperties.All)]
LookupType
。后者告诉设计者,如果 属性 发生变化,它应该重新查询所有属性(不仅仅是值)。 TypeConverter 仅提供匹配的属性。
对于Visual Studio中的IntelliSense没有解决办法,但是如果你实现了如上所示的属性,至少你可以保持属性值一致。
最后一点:Visual Studio 缓存设计器中使用的控件。因此,如果您进行更改,您可能需要清理解决方案并重新启动 VS 以使更改生效。
我有一个执行查找的 UserControl。它执行的查找类型取决于名为 LookupType 的 属性。 UserControl 中有与每个 LookupType 相关的属性。因此,例如,LookupType = Vendor 具有 Vendor_RemitToAddr 等属性,而 LookupType = ShipMeth 具有 ShipMeth_ShipMethID.
等属性Intellisense 和 Properties window 显示了所有这些,这是有道理的。但我希望能够让 UserControl 仅公开与所选 LookupType 相关的属性。
有什么方法可以根据 LookupType 更改属性的访问修饰符 属性?
注意:这与其说是功能问题,不如说是用户体验问题。查找工作正常。但是在开发的时候看起来乱七八糟,开发者-用户可以误设置错误属性。
这是一个只有 3 个属性的 UserControl 的简化示例:LookupType
、RemitToAddr
(仅对 LookupType.Vendor 有效)、ShipMethID
(仅对 LookupType.ShipMeth).首先,LookupControl
:
public enum LookupType
{
Vendor,
ShipMeth
}
[TypeConverter(typeof(LookupControlConverter))]
public partial class LookupControl : UserControl
{
private LookupType lookupType;
public LookupControl()
{
InitializeComponent();
}
[RefreshProperties(RefreshProperties.All)]
[Browsable(true)]
public LookupType LookupType
{
get => lookupType;
set
{
lookupType = value;
// Clear out unwanted property values
switch (value)
{
case LookupType.Vendor:
ShipMethID = null;
break;
case LookupType.ShipMeth:
RemitToAddr = null;
break;
}
}
}
[Browsable(true)]
public string RemitToAddr { get; set; }
[Browsable(true)]
public string ShipMethID { get; set; }
}
LookupControl 在 LookupType
属性 setter 中包含一些逻辑,用于清除对当前 LookupType 没有意义的属性值。这可以确保您的控件不会有不一致的 属性 值。
对于 Windows Forms Designer 中的 PropertyGrid,我实现了 TypeConverter
:
internal sealed class LookupControlConverter : TypeConverter
{
private readonly PropertyDescriptorCollection allProps = TypeDescriptor.GetProperties(typeof(LookupControl), new[] { BrowsableAttribute.Yes });
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
if (context?.Instance is LookupControl)
return true;
return base.GetPropertiesSupported(context);
}
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
if (context.Instance is LookupControl control)
{
var propList = allProps.Cast<PropertyDescriptor>().ToList();
// Remove the unwanted property descriptors based on the current value of LookupType
switch (control.LookupType)
{
case LookupType.Vendor:
propList.Remove(allProps[nameof(LookupControl.ShipMethID)]);
break;
case LookupType.ShipMeth:
propList.Remove(allProps[nameof(LookupControl.RemitToAddr)]);
break;
}
return new PropertyDescriptorCollection(propList.ToArray(), true);
}
return allProps;
}
}
注意:要使LookupControlConverter
生效,需要在用户控件上应用[TypeConverter(typeof(LookupControlConverter))]
属性,在属性上应用[RefreshProperties(RefreshProperties.All)]
LookupType
。后者告诉设计者,如果 属性 发生变化,它应该重新查询所有属性(不仅仅是值)。 TypeConverter 仅提供匹配的属性。
对于Visual Studio中的IntelliSense没有解决办法,但是如果你实现了如上所示的属性,至少你可以保持属性值一致。
最后一点:Visual Studio 缓存设计器中使用的控件。因此,如果您进行更改,您可能需要清理解决方案并重新启动 VS 以使更改生效。