2

我已经阅读了很多关于 Winforms ComboBox ValueMember 属性主题的有用帖子,但没有一个回答我的具体问题。首先,我将描述一个运行良好的简单示例,然后我将描述我想如何更改它,并询问如何做到这一点(我还将提供我的一个尝试)。

首先,工作示例。只是一个带有组合框控件的表单,以及这段代码:

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;
        }
    }
}

我的问题是,如何最好地利用此扩展方法,同时保留从枚举值列表构建组合框项的能力,并能够通过枚举值设置选定的组合框项(或值)?

下面是我的第一次尝试。我创建了一个简单的类来包装枚举值和显示字符串,并将组合框 DisplayMember 和 ValueMember 设置为新类的属性。这部分有效;组合框的项目使用显示值正确填充,但我无法设置 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);

一切都像一个魅力。我仍然不确定为什么按值设置不起作用,但这是解决问题的一个非常紧凑的解决方案。但不如响应标记为答案那么紧凑!

4

4 回答 4

4

在您的第一次尝试中,您可以选择所需的项目:

comboBox1.SelectedItem = comboBox1.Items.Cast<ValueDisplayEnum>().First(x => (Enum1)x.Value == Enum1.MultiWordValue2);
于 2013-05-07T16:31:54.313 回答
3

一个通用实用程序类,它使用枚举字段上的描述属性来控制组合框中枚举的显示值。

    /// <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
...
于 2013-05-08T04:54:46.647 回答
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;
    }
}
于 2013-05-07T14:20:31.630 回答
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; }
        }

如您所见,您可以设置显示和值成员来分隔数据和视图。

于 2013-05-07T14:39:47.663 回答