簡體   English   中英

應用程序范圍內的控件默認值

[英]Application-wide control defaults

我正在尋找一種在C#.NET Windows應用程序中為不同類型的控件設置自己的默認屬性值的方法。 默認屬性值應“覆蓋”控件的現有默認值,但仍可以通過在設計器中顯式設置屬性值來“覆蓋”。

這是為了簡化客戶端(或我本人)第十次改變主意時更改默認外觀/控件行為的過程。 這尤其涉及到諸如DataGridView或第3方控件之類的控件,其中需要維護大量與布局相關的屬性。

我知道創建繼承的控件並使用DefaultValue屬性的能力,但這不是我正在尋找的解決方案 ,原因有兩個:

  • 不得不繼承我要為其指定自定義屬性的每種控件的麻煩,更不用說覆蓋/陰影化屬性並設置DefaultValue屬性了。
  • 我不能再使用標准的.NET控件,而必須使用繼承的控件。
  • 繼承控件的數量會隨着時間的推移而增加,並使工具箱變得混亂。
  • 我自己或項目中的其他開發人員在匆忙時忘記使用新的繼承類型,從而導致控件的行為/外觀不一致。

這是我想象的它將起作用的方式:

  • 示例1:默認情況下, DataGridView的背景色為SystemColors.Window 我將自己的默認值設置為Color.BlueColor.Blue離譜了!)。 在設計器中,使用默認的背景色,即未在.designer.cs文件中明確設置背景色。 運行應用程序時,將執行一部分代碼,從而使網格變成藍色,這是我指定的。

  • 示例2:在設計器中,同一DataGridView的背景色設置為Color.Red 這將覆蓋我自己的默認值blue,即在設計時和運行時都在網格中顯示紅色背景。


對我來說,解決方案是使用反射來檢查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);
  }
}

雖然不如泛型那么漂亮,但您也許可以通過Control Builders進行一些操作以實現這一目標。

編輯:

昨晚,我使用ControlBuilder對通用包裝控件進行了快速原型設計。 我對結果不滿意。 雖然您可能可以使它工作,但我相信一個新的Page或Container類可能會更簡單。 我在測試中使用的源代碼可在我的博客上找到

我已經使用或可以想到幾種解決方案。

  1. 繼承控件,但是您已經提到了。
  2. 一些更高級的控件庫(如DevExpress)具有內置功能,可從配置文件(對於DevExpress,則為XML)加載布局,甚至完全可換膚(對於DevExpress也是如此)。
  3. 有時,我為控件創建擴展方法,並在用戶控件或窗體的構造函數中調用它們。 這是啟用或禁用功能集(例如排序)的簡單方法。 數據網格中的多選或列重新排序,並提供一致的行為和外觀。
  4. 使用數據綁定並將屬性綁定到某些配置數據。 我相信甚至還有內置功能-用戶設置或類似功能-但我從未使用過此功能。
  5. 在大型項目中,像上面建議的那樣在所有控件上調用擴展方法不是很方便。 您可以在創建窗體時遞歸訪問所有控件,查看屬性,將其與默認值進行比較(使用反射來獲取DefaultValue屬性),如果它們不匹配(也就是說,該值已在中覆蓋)設計人員)從某些文件或內存存儲中加載默認值並應用它。

您可以改為覆蓋頁面,並循環瀏覽所有控件,例如

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM