Значения по умолчанию для всего приложения - PullRequest
1 голос
/ 28 августа 2009

Я ищу способ настроить собственные значения свойств по умолчанию для различных типов элементов управления в моем приложении Windows на C # .NET. Значения свойств по умолчанию должны «переопределять» существующие значения по умолчанию для элементов управления, но при этом должны быть «переопределены», если явно установить значения свойств в конструкторе.

Это должно упростить процесс изменения внешнего вида / поведения элементов управления по умолчанию, когда клиент (или я) передумал в 10-й раз. Это особенно относится к элементам управления, таким как DataGridView или сторонним элементам управления, где необходимо сохранить множество свойств, связанных с макетом.

Мне известна возможность создавать унаследованные элементы управления и использовать атрибут DefaultValue, но это не решение, которое я ищу по нескольким причинам:

  • Это проблема, связанная с наследованием каждого типа элемента управления, для которого я хочу указать пользовательские свойства, не говоря уже о переопределении / затенении свойств и установке атрибута DefaultValue.
  • Я больше не могу использовать стандартные элементы управления .NET, но вынужден использовать унаследованные элементы управления.
  • Количество унаследованных элементов управления со временем увеличивается и загромождает набор инструментов.
  • Я или другие разработчики проекта забываем использовать новые унаследованные типы во время поспешности, что приводит к неосторожному поведению / появлению элементов управления.

Вот как я представлял, что это будет работать:

  • Пример 1: A DataGridView по умолчанию имеет цвет фона SystemColors.Window. Я установил свой собственный значение по умолчанию Color.Blue (как возмутительно!). В дизайнере используется цвет фона по умолчанию, т.е. цвет фона не установлен явно в файле .designer.cs. При запуске приложения часть кода выполняется, что приводит к повороту сетки синий, как указано мной.

  • Пример 2: Для того же цвета фона DataGridView установлено значение Color.Red в конструкторе. это переопределяет мое собственное значение по умолчанию синего цвета, показывая красный фон в сетке, как во время разработки, так и во время выполнения.


Решение

Решением для меня было использование отражения для проверки атрибута DefaultValue, как предлагает Даниэль Брюкнер .

Я проверяю все элементы управления в форме, вызывая 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);
  }
}

Ответы [ 3 ]

3 голосов
/ 28 августа 2009

Хотя это и не так красиво, как у дженериков, вы могли бы кое-что сделать с Control Builders , чтобы справиться с этим.

Edit:

Прошлой ночью я сделал быстрый прототип универсального элемента управления-обертки с помощью ControlBuilder. Я не доволен результатами. Хотя вы, вероятно, можете заставить его работать, я полагаю, что новый класс Page или Container может оказаться намного проще. Исходный код, который я использовал в своем тесте, доступен в моем блоге .

2 голосов
/ 28 августа 2009

Есть несколько решений, которые я использовал или могу придумать.

  1. Наследование элемента управления, но вы уже упоминали об этом.
  2. Некоторые более продвинутые управляющие библиотеки (например, DevExpress) имеют встроенную возможность загружать макет из файлов конфигурации (XML в случае DevExpress) или даже полностью скины (также для DevExpress).
  3. Иногда я создаю метод расширения для элементов управления и вызываю их в конструкторе пользовательского элемента управления или формы. Это простой способ включить или отключить набор функций, таких как сортировка. множественный выбор или переупорядочение столбцов в сетках данных и дает согласованное поведение и внешний вид.
  4. Использовать привязку данных и привязывать свойства к некоторым данным конфигурации. Я считаю, что есть даже встроенная функциональность - пользовательские настройки или что-то в этом роде - но я никогда не использовал эту функцию.
  5. Вызов метода расширения для всех элементов управления, как предложено выше, не очень удобен в больших проектах. Вы можете рекурсивно посетить все элементы управления в форме при ее создании, посмотреть на свойства, сравнить со значением по умолчанию (используя отражение, чтобы получить атрибут DefaultValue), и если они не совпадают (то есть значение было переопределено в конструктор) загрузите значение по умолчанию из какого-либо файла или хранилища в памяти и примените его.
1 голос
/ 28 августа 2009

вместо этого вы можете перезаписать страницу и выполнить цикл по всем элементам управления, например,

foreach (Control c in Page.Controls)
{
   if (c is Textbox)
   {
       (Textbox)c.Color.blah.blah.blah ;)
   }
   ///etc
   Recurse through (c.Controls);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...