2013-05-07 65 views
2

我已經閱讀了WinForms ComboBox的ValueMember屬性的主題很多有用的帖子,但他們都沒有回答我的具體問題。首先,我將描述一個簡單的例子,它可以正常工作,然後我將描述我想如何改變它,並詢問如何做到這一點(我也會提供我的一個嘗試)。通過ValueMember的ValueMember選擇類的屬性

一,工作示例。只是一個帶有comboBox控件的表單,並且此代碼如下:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     comboBox1.DataSource = Enum.GetValues(typeof(Enum1)); 
     comboBox1.SelectedItem = Enum1.MultiWordValue2; 
    } 
} 

public enum Enum1 : int 
{ 
    Undefined, 
    MultiWordValue1, 
    MultiWordValue2 
} 

沒問題,這工作得很好。我運行應用程序,comboBox獲取適當的項目,並選擇適當的值。

但是,這些枚舉值是醜陋的,我希望我的用戶有更好的體驗,所以我創建了一個擴展方法,使值更好地顯示。

public static class ExtensionMethods 
{ 
    public static string ToDisplayString(this Enum1 me) 
    { 
     switch (me) 
     { 
      case Enum1.MultiWordValue1: 
       return "Multi Word Value 1"; 
      case Enum1.MultiWordValue2: 
       return "Multi Word Value 2"; 
      default: 
       return string.Empty; 
     } 
    } 
} 

我的問題是,如何最好我利用這個擴展方法,同時保持從枚舉值的列表構建組合框項目,並能夠通過設置選定ComboBox項(或價值)的能力枚舉值?

以下是我的第一次嘗試。我創建了一個簡單的類來包裝枚舉值和顯示字符串,並將組合框DisplayMember和ValueMember設置爲新類的屬性。這部分工作; ComboBox的項目與顯示值正確填充,但我不能設置的SelectedValue:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     comboBox1.DisplayMember = "Display"; 
     comboBox1.ValueMember = "Value"; 
     foreach (Enum1 e in Enum.GetValues(typeof(Enum1))) 
      comboBox1.Items.Add(new ValueDisplayEnum(e, e.ToDisplayString())); 
     comboBox1.SelectedValue = Enum1.MultiWordValue2; 
    } 
} 

public enum Enum1 : int 
{ 
    Undefined, 
    MultiWordValue1, 
    MultiWordValue2 
} 

public static class ExtensionMethods 
{ 
    public static string ToDisplayString(this Enum1 me) 
    { 
     switch (me) 
     { 
      case Enum1.MultiWordValue1: 
       return "Multi Word Value 1"; 
      case Enum1.MultiWordValue2: 
       return "Multi Word Value 2"; 
      default: 
       return string.Empty; 
     } 
    } 
} 

public class ValueDisplayEnum 
{ 
    public object Value { get; set; } 
    public string Display { get; set; } 
    private ValueDisplayEnum() { } 
    public ValueDisplayEnum(object _Value, string _Display) 
    { 
     Value = _Value; 
     Display = _Display; 
    } 
} 

爲什麼不設置的SelectedValue這樣的工作?我該如何完成一個更好的顯示字符串的枚舉組合框?

另:我認爲這可能是因爲ValueDisplayEnum的Value屬性的底層數據類型是一個對象,而不是Enum1。但是,如果將類型更改爲Enum1,則SelectedValue仍然無法正確設置。

感謝您的幫助!

編輯1:指定由Mike基於所述建議的一個解決方案:

添加以下模板化方法:

public static void SetEnumCombo<T>(ComboBox _ComboBox, T _Value) 
{ 
    foreach (ValueDisplayEnum vde in _ComboBox.Items) 
     if (((T)vde.Value).Equals(_Value)) 
      _ComboBox.SelectedItem = vde; 
} 

而不是指定直接的SelectedValue或selectedItem的,稱此:

foreach (Enum1 e in Enum.GetValues(typeof(Enum1))) 
    comboBox1.Items.Add(new ValueDisplayEnum(e, e.ToDisplayString())); 
SetEnumCombo(comboBox1, Enum1.MultiWordValue2); 

一切都像魅力一樣。我仍然不確定爲什麼按價值設置不起作用,但這是解決問題的非常緊湊的解決方案。但並不像回答那樣緊湊!

+0

好設置的SelectedValue不工作,因爲你有字符串數據,並希望與枚舉值來選擇它的組合框。 – wonko79 2013-05-07 14:18:45

+0

你可能也想看到這個如何做 - 我 - 覆蓋-tostring-in-c-sharp-enums – nawfal 2013-06-08 22:25:12

回答

4

在你的第一次嘗試,您可以用選擇需要的項目:

comboBox1.SelectedItem = comboBox1.Items.Cast<ValueDisplayEnum>().First(x => (Enum1)x.Value == Enum1.MultiWordValue2); 
+0

Woa不錯。更緊湊,並取代了我創建的模板化方法。太好了!謝謝你! – Jason 2013-05-07 16:43:09

+0

@ Lucky3 - 很棒的解決方案。我會補充一點,如果你試圖將一個combobox數據綁定的值成員添加到數據表中,請進行編輯: combobox1.SelectedItem = combobox1.Items.Cast ()。首先(x => (字符串)(((DataRowView)x)[「ValueMemberColumnName」])== 「DesiredValueMemberValue」); 也就是說,只要您的值成員列數據類型是字符串。否則,改變字符串轉換,比較和文字。 – 2014-03-12 20:24:59

1

我喜歡以下解決方案,因爲您在一個位置添加或更改枚舉及其字符串值 - 在數組extendedEnumerations中。

public partial class Form1 : Form 
{ 
    public enum MyEnum 
    { 
     EnumValue1, 
     EnumValue2, 
     EnumValue3 
    } 

    public class EnumExtension 
    { 
     public MyEnum enumValue; 
     public String enumString; 
     public EnumExtension(MyEnum enumValue, String enumString) 
     { 
      this.enumValue = enumValue; 
      this.enumString = enumString; 
     } 
     public override string ToString() 
     { 
      return enumString; 
     } 
    } 

    private EnumExtension[] extendedEnumerations = 
    { 
     new EnumExtension(MyEnum.EnumValue1, "Enum Value 1"), 
     new EnumExtension(MyEnum.EnumValue2, "Enum Value 2"), 
     new EnumExtension(MyEnum.EnumValue3, "Enum Value 3"), 
    }; 

    public Form1() 
    { 
     InitializeComponent(); 
     foreach (EnumExtension nextEnum in extendedEnumerations) 
      comboBox1.Items.Add(nextEnum); 
     comboBox1.SelectedIndexChanged += new EventHandler(comboBox1_SelectedIndexChanged); 

     button1.Click += new EventHandler(button1_Click); 
     button2.Click += new EventHandler(button2_Click); 
     button3.Click += new EventHandler(button3_Click); 
    } 

    void button3_Click(object sender, EventArgs e) 
    { 
     comboBox1.SelectedItem = extendedEnumerations[2]; 
    } 

    void button2_Click(object sender, EventArgs e) 
    { 
     SetSelectedEnumeration(MyEnum.EnumValue2); 
    } 

    void button1_Click(object sender, EventArgs e) 
    { 
     SetSelectedEnumeration(MyEnum.EnumValue1); 
    } 

    private void SetSelectedEnumeration(MyEnum myEnum) 
    { 
     foreach (EnumExtension nextEnum in comboBox1.Items) 
     { 
      if (nextEnum.enumValue == myEnum) 
      { 
       comboBox1.SelectedItem = nextEnum; 
       break; 
      } 
     } 
    } 

    void comboBox1_SelectedIndexChanged(object sender, EventArgs e) 
    { 
     EnumExtension selectedExtension = (EnumExtension)comboBox1.SelectedItem; 
     MyEnum selectedValue = selectedExtension.enumValue; 
    } 
} 
+0

有趣。這比我期望的還要多一點樣板(每個枚舉類都有一個類),但我會試試看!也許給每個擴展類一個返回它可能的EnumExtension實例的靜態成員會使它消耗很容易? – Jason 2013-05-07 15:12:24

+0

更多的數據,更少的代碼(沒有切換條款)。我總是喜歡維護數據數組的內容而不是修改代碼。選擇你的毒藥。 – Mike 2013-05-07 15:16:36

+0

那麼,foreach解決方案本身的做法,現在保持與我的枚舉泛型ValueDisplayEnum類的技巧。我只是添加了你的SetSelectedEnumeration邏輯來找到正確的項目,並設置SelectedItem而不是SelectedValue,它的工作原理!所以謝謝你!這對我來說已經足夠好了,但我肯定會將EnumExtension類視爲一個單獨而有趣的概念。 – Jason 2013-05-07 15:23:32

0

好設置的SelectedValue不工作,因爲你有字符串數據,並希望與枚舉值來選擇它。

一個簡單的解決辦法是這樣的:

private static void FillCombo(ComboBox box) 
     { 
      List<DisplayableStatus> ds = new List<DisplayableStatus>(); 
      foreach (var val in Enum.GetValues(typeof(Status))) 
       ds.Add(new DisplayableStatus { Status = (Status)val, DisplayText = val.ToString() + " Nice" }); 

      box.DataSource = ds; 
      box.DisplayMember = "DisplayText"; 
      box.ValueMember = "Status"; 

      box.SelectedValue = Status.Stop; 
     } 

     public enum Status 
     { 
      Unknown, 
      Start, 
      Stop 
     } 

     public class DisplayableStatus 
     { 
      public Status Status { get; set; } 
      public string DisplayText { get; set; } 
     } 

正如你可以看到你可以設置顯示器和值成員單獨的數據和觀點。

+0

我不確定我是否同意我有comboBox Value的字符串數據。看看這一行:comboBox1.Items.Add(new ValueDisplayEnum(e,e.ToDisplayString()));我正在提供一個類作爲comboBox項目。組合框的ValueMember是「Value」,它在對象上不是字符串。價值是枚舉。但是,它看起來像是從類的列表中數據綁定組合框,而不是僅添加項目。我會試着看看它是否有效。 – Jason 2013-05-07 14:50:44

+0

沒有你是對的。我監督了這一點。您的值是typeof對象,並且您希望將所選值設置爲具有相同結果的typeof Enum1。使ValueDisplayEnum類型的Enum1,而不是對象,並在foreach中強制轉換爲Enum1。 – wonko79 2013-05-07 14:55:02

+0

其實,我試過(正如我在原來的帖子中提到的那樣),它沒有奏效。我將ValueDisplayEnum.Value屬性設置爲Enum1而不是對象,但它沒有改變行爲。 SelectedValue分配仍然無效。 – Jason 2013-05-07 15:10:01

3

使用Description屬性上枚舉字段,用於控制顯示值在組合框中選擇一個枚舉一個通用的實用工具類。

/// <summary> 
    /// Return the contents of the enumeration as formatted for a combo box 
    /// relying on the Description attribute containing the display value 
    /// within the enum definition 
    /// </summary> 
    /// <typeparam name="T">The type of the enum being retrieved</typeparam> 
    /// <returns>The collection of enum values and description fields</returns> 
    public static ICollection<ComboBoxLoader<T>> GetEnumComboBox<T>() 
    { 
     ICollection<ComboBoxLoader<T>> result = new List<ComboBoxLoader<T>>(); 
     foreach (T e in Enum.GetValues(typeof(T))) 
     { 
      ComboBoxLoader<T> value = new ComboBoxLoader<T>(); 
      try 
      { 
       value.Display = GetDescription(e); 
      } 
      catch (NullReferenceException) 
      { 
       // This exception received when no Description attribute 
       // associated with Enum members 
       value.Display = e.ToString(); 
      } 
      value.Value = e; 
      result.Add(value); 
     } 
     return result; 
    } 

要在數據網格視圖中使用它的窗體上,例如:

 DataGridViewComboBoxColumn trussLocationComboBoxColumn = trussLocationColumn as DataGridViewComboBoxColumn; 
     trussLocationComboBoxColumn.DataSource = EnumUtils.GetEnumComboBox<TrussLocationCase>(); 
     trussLocationComboBoxColumn.DisplayMember = "Display"; 
     trussLocationComboBoxColumn.ValueMember = "Value"; 

和對被拾取的顯示字段

public enum TrussLocationCase 
{ 
    [Description("All Cases")] 
    AllCases, 
    [Description("1A")] 
    OneA, 
    [Description("1B")] 
    OneB, 
    [Description("2C")] 

枚舉字段的說明並完成它的一切,ComboBoxLoader類

/// <summary> 
/// Class to provide assistance for separation of concern 
/// over contents of combo box where the 
/// displayed value does not match the ToString 
/// support. 
/// </summary> 
/// <typeparam name="T">The type of the value the combo box supports</typeparam> 
[DebuggerDisplay("ComboBoxLoader {Display} {Value.ToString()}")] 
public class ComboBoxLoader<T> 
{ 
    /// <summary> 
    /// The value to display in the combo box 
    /// </summary> 
    public string Display { get; set; } 

    /// <summary> 
    /// The actual object associated with the combo box item 
    /// </summary> 
    public T Value { get; set; } 
} 

會看到填充

All Cases 
1A 
1B 
2C 
... 
+0

這看起來像我最初嘗試的枚舉值/顯示包裝器的更健壯的版本。這不是我最終使用的,但如果我的聲望足夠高,我會完全+1。感謝您的建議,如果我的需求變得更加複雜,我一定會保持這種方便。 – Jason 2013-05-09 13:43:50

相關問題