我正在寻找一种方法来为我的C#.NET Windows应用程序中的不同类型的控件设置我自己的默认属性值。默认属性值应“覆盖”控件的现有默认值,但仍可通过在设计器中显式设置属性值来“覆盖”。
这是为了简化在客户端(或我自己)第10次改变主意时更改控件的默认外观/行为的过程。这尤其涉及DataGridView
或第三方控件等控件,其中需要维护大量与布局相关的属性。
我知道能够创建继承的控件并使用DefaultValue
属性,但这不是我正在寻找的解决方案,原因有两个:
这就是我想象它会起作用的方式:
示例1:默认情况下,DataGridView
具有背景色
SystemColors.Window
。我自己设定
默认值为Color.Blue
(如何
岂有此理!)。在设计师,
使用默认背景颜色,
即没有设置背景颜色
明确地在.designer.cs文件中。
运行应用程序时,会执行一部分代码,导致网格转动
蓝色,由我指定。
示例2:同一DataGridView
的背景颜色设置为
设计师Color.Red
。这个
覆盖我自己的默认值蓝色,显示红色背景
在网格中,无论是在设计时还是在运行时。
我的解决方案是使用反射检查DefaultValue
属性,如Daniel Brückner所示。
我递归表单上的所有控件,为每个控件调用SetDefaultValues
。对于要设置的每个属性值,我调用SetValue
方法,该方法确保仅设置未从其默认值更改的属性。
这种方法存在一个缺陷,但。已在设计器中显式设置但与默认值不同的属性将被SetValue
方法覆盖。
void SetDefaultValues(Control control)
{
if (control is DataGridView)
{
SetValue(control, "BackColor", Color.Blue);
}
else if (control is TextBox)
{
// etc.
}
}
private static void SetValue(object control, string propertyName, object newValue)
{
System.Reflection.PropertyInfo prop = control.GetType().GetProperty(propertyName);
if (prop == null)
{
throw new ArgumentException(string.Format(
"Specified property \"{0}\" does not exist on type \"{1}\".", prop.Name, control.GetType().FullName),
"propertyName");
}
bool defaultValueFound = false;
object defaultValue = null;
foreach (object attr in prop.GetCustomAttributes(true))
{
if (attr is DefaultValueAttribute)
{
defaultValue = ((DefaultValueAttribute)attr).Value;
defaultValueFound = true;
break;
}
}
if (!defaultValueFound && prop.PropertyType.IsValueType)
{
// Get default value for value types if no default value was specified by attributes:
defaultValue = Activator.CreateInstance(prop.PropertyType);
}
if (defaultValue == null || defaultValue.Equals(prop.GetValue(control, null)))
{
// If default value matches current value, set new value:
prop.SetValue(control, newValue, null);
}
}
答案 0 :(得分:3)
虽然没有仿制药那么漂亮,但您可以使用Control Builders做一些事情来解决这个问题。
修改强>
昨晚我用ControlBuilder做了一个通用包装器控件的快速原型。我对结果不满意。虽然你可以让它工作,但我相信一个新的Page或Container类可能是一个更简单的结果。我在我的测试中使用的源代码可以在我的blog上使用。
答案 1 :(得分:2)
我使用过或者我能想到的几种解决方案。
答案 2 :(得分:1)
你可以覆盖页面,并循环遍历所有控件,例如
foreach (Control c in Page.Controls)
{
if (c is Textbox)
{
(Textbox)c.Color.blah.blah.blah ;)
}
///etc
Recurse through (c.Controls);
}