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. 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.
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:
- It's a hassle having to inherit of every type of control I want to specify custom properties for, not to mention overriding/shadowing the properties and setting the DefaultValue attribute.
- I can no longer use the standard .NET controls, but have to use the inherited controls.
- The number of inherited controls increases over time and clutters up the toolbox.
- Myself or other developers on the project forget to use the new inhertied types in times of haste, resulting in inconsitent behaviour/appearance of controls.
This is how I imagined that it will work:
Example 1: A
DataGridView
by default has background colorSystemColors.Window
. I set my own default value toColor.Blue
(how outrageous!). In the designer, the default background color is used, i.e. the background color is not set explicitly in the .designer.cs file. 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 toColor.Red
in the designer. This overrides my own default value of blue, showing a red background in the grid, both in design-time and run-time.
Solution
The solution for me was to use reflection to check the DefaultValue
attribute, as suggested by Daniel Brückner.
I recurse through all controls on a form, calling SetDefaultValues
for each control. 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.
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.
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);
}
}