[英]Application-wide control defaults
I'm looking for a way to set up my own default property values for different types of controls in my C# .NET windows application. 我正在寻找一种在C#.NET Windows应用程序中为不同类型的控件设置自己的默认属性值的方法。 The default property values should 'override' the existing default values of the controls, but still be 'overridable' by setting the property values explicitly in the designer. 默认属性值应“覆盖”控件的现有默认值,但仍可以通过在设计器中显式设置属性值来“覆盖”。
This is to simplify the process of changing default appearance/behaviour of controls when the client (or myself) change their mind for the 10th time. 这是为了简化客户端(或我本人)第十次改变主意时更改默认外观/控件行为的过程。 This relates especially to controls like the DataGridView
or 3rd party controls where there are tons of layout-related properties to maintain. 这尤其涉及到诸如DataGridView
或第3方控件之类的控件,其中需要维护大量与布局相关的属性。
I am aware of the ability to create inherited controls and use the DefaultValue
attribute, but this is not the solution I'm looking for for a couple of reasons: 我知道创建继承的控件并使用DefaultValue
属性的能力,但这不是我正在寻找的解决方案 ,原因有两个:
This is how I imagined that it will work: 这是我想象的它将起作用的方式:
Example 1: A DataGridView
by default has background color SystemColors.Window
. 示例1:默认情况下, DataGridView
的背景色为SystemColors.Window
。 I set my own default value to Color.Blue
(how outrageous!). 我将自己的默认值设置为Color.Blue
( Color.Blue
离谱了!)。 In the designer, the default background color is used, ie the background color is not set explicitly in the .designer.cs file. 在设计器中,使用默认的背景色,即未在.designer.cs文件中明确设置背景色。 When running the application, a portion of code is executed, causing the grid to turn blue, as specified by me. 运行应用程序时,将执行一部分代码,从而使网格变成蓝色,这是我指定的。
Example 2: The background color of the same DataGridView
is set to Color.Red
in the designer. 示例2:在设计器中,同一DataGridView
的背景色设置为Color.Red
。 This overrides my own default value of blue, showing a red background in the grid, both in design-time and run-time. 这将覆盖我自己的默认值blue,即在设计时和运行时都在网格中显示红色背景。
The solution for me was to use reflection to check the DefaultValue
attribute, as suggested by Daniel Brückner . 对我来说,解决方案是使用反射来检查DefaultValue
属性,所建议丹尼尔·布鲁克纳 。
I recurse through all controls on a form, calling SetDefaultValues
for each control. 我遍历窗体上的所有控件,为每个控件调用SetDefaultValues
。 For each property value to set, I call the SetValue
method, which makes sure only properties that haven't been changed from their default values, are set. 对于每个要设置的属性值,我调用SetValue
方法,该方法确保仅设置未更改其默认值的属性。
There is one flaw in this approach, though . 但是,这种方法有一个缺陷 。 Properties that have been set explicitly in the designer, but do not differ from their default values, will be overwritten by the SetValue
method. 在设计器中已明确设置但与默认值没有区别的属性将被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);
}
}
While not as pretty as generics, you might me able to do something with Control Builders to pull this off. 虽然不如泛型那么漂亮,但您也许可以通过Control Builders进行一些操作以实现这一目标。
Edit: 编辑:
Last night I did a quick prototype of a generic wrapper control with the ControlBuilder. 昨晚,我使用ControlBuilder对通用包装控件进行了快速原型设计。 I am not happy with the results. 我对结果不满意。 While you can probably get it to work, I beleive a new Page or Container class might be a much simpler result. 虽然您可能可以使它工作,但我相信一个新的Page或Container类可能会更简单。 The source code I used in my test is avalible on my blog . 我在测试中使用的源代码可在我的博客上找到 。
There are several solutions I have used or I can think of. 我已经使用或可以想到几种解决方案。
you could overide page instead and have a loop through all the controls eg 您可以改为覆盖页面,并循环浏览所有控件,例如
foreach (Control c in Page.Controls)
{
if (c is Textbox)
{
(Textbox)c.Color.blah.blah.blah ;)
}
///etc
Recurse through (c.Controls);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.