Ràng buộc một enum vào một hộp tổ hợp WinForms, rồi đặt nó


122

rất nhiều người đã trả lời câu hỏi làm thế nào để liên kết một enum với một hộp tổ hợp trong WinForms. Nó như thế này:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));

Nhưng điều đó khá vô ích nếu không thể đặt giá trị thực tế để hiển thị.

Tôi đã thử:

comboBox1.SelectedItem = MyEnum.Something; // Does not work. SelectedItem remains null

Tôi cũng đã thử:

comboBox1.SelectedIndex = Convert.ToInt32(MyEnum.Something); // ArgumentOutOfRangeException, SelectedIndex remains -1

Có ai có bất kỳ ý tưởng làm thế nào để làm điều này?


2
Tại sao không thử ComboBox.SelectedValue thay thế?
Oliver Friedrich

5
Nếu câu hỏi của bạn đã được trả lời, bạn thực sự nên chọn một câu trả lời.
Ryan The Leach

Quan điểm của việc kết hợp một enum không hoàn toàn rõ ràng. Một enum có thể sẽ không thay đổi trong thời gian chạy. Bạn cũng có thể viết một phương thức mở rộng sẽ điền vào bộ sưu tập các mục của combobox với tất cả các giá trị của enum.
Andreas


@OliverFriedrich SelectedValuegây ra sự cố InvalidOperationExceptioncho tôi. "Không thể đặt SelectedValuetrong a ListControlvới giá trị trống ValueMember."
Tyler

Câu trả lời:


161

The Enum

public enum Status { Active = 0, Canceled = 3 }; 

Đặt các giá trị thả xuống từ nó

cbStatus.DataSource = Enum.GetValues(typeof(Status));

Lấy enum từ mục đã chọn

Status status; 
Enum.TryParse<Status>(cbStatus.SelectedValue.ToString(), out status); 

5
Cảm ơn, điều này làm việc cho tôi. Hãy nhớ rằng tryparse là một câu lệnh .net 4.0.
real_yggdrasil

Đối với tôi, SelectedValue luôn rỗng. Có vẻ như hộp kết hợp không được phức tạp hóa. (myEnum) this.GridView.CurrentRow.Cells ["comboColumnCell"]. Giá trị. Tôi có thể thấy giá trị nhưng bên trong nó ném ra ngoại lệ con trỏ null
ssal

3
Đây chính xác là cách mà OP không muốn sử dụng. Vấn đề là người dùng được hiển thị tên trong mã của mỗi giá trị, điều này có thể được tái cấu trúc và không thân thiện với người dùng hầu hết các lần.
Alejandro

5
Tại sao sử dụng TryParse thay vì Parse? ... var status (Trạng thái) Enum.Parse (typeof (Status), cbStatus.SelectedValue.ToString ()); ... Bạn ràng buộc enum với combobox để bạn BIẾT rằng giá trị phải là giá trị enum hợp lệ và nếu Nó không phải là một cái gì đó đã xảy ra rất sai và bạn có thể muốn một ngoại lệ.
bytedev

1
Tại sao điều này được ủng hộ vào quên lãng? Câu hỏi đặt ra là làm thế nào để lập trình giá trị đã chọn của hộp tổ hợp, sử dụng một trong các giá trị của enum.
Tyler

39

Để đơn giản hóa:

Đầu tiên Khởi tạo lệnh này: (ví dụ: sau InitalizeComponent())

yourComboBox.DataSource =  Enum.GetValues(typeof(YourEnum));

Để truy xuất mục đã chọn trên combobox:

YourEnum enum = (YourEnum) yourComboBox.SelectedItem;

Nếu bạn muốn đặt giá trị cho hộp kết hợp:

yourComboBox.SelectedItem = YourEnem.Foo;

2
Điều này hoạt động miễn là giá trị Hiển thị giống với thành viên Giá trị, nếu không thì không.
Lord of Scripts

15

Mật mã

comboBox1.SelectedItem = MyEnum.Something;

là ok, vấn đề phải nằm trong DataBinding. Các phép gán DataBinding xảy ra sau hàm tạo, chủ yếu là lần đầu tiên hộp tổ hợp được hiển thị. Cố gắng đặt giá trị trong sự kiện Tải. Ví dụ: thêm mã này:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    comboBox1.SelectedItem = MyEnum.Something;
}

Và kiểm tra xem nó có hoạt động không.


12

Thử:

comboBox1.SelectedItem = MyEnum.Something;

CHỈNH SỬA:

Rất tiếc, bạn đã thử nó rồi. Tuy nhiên, nó hoạt động với tôi khi comboBox của tôi được đặt thành DropDownList.

Đây là mã đầy đủ của tôi phù hợp với tôi (với cả DropDown và DropDownList):

public partial class Form1 : Form
{
    public enum BlahEnum
    { 
        Red,
        Green,
        Blue,
        Purple
    }

    public Form1()
    {
        InitializeComponent();

        comboBox1.DataSource = Enum.GetValues(typeof(BlahEnum));

    }

    private void button1_Click(object sender, EventArgs e)
    {
        comboBox1.SelectedItem = BlahEnum.Blue;
    }
}

thật thú vị, thật tuyệt khi bạn có thể thực hiện `comboBox1.SelectedItem = BlahEnum.Blue;` nhưng Điều gì sẽ xảy ra nếu bạn muốn những thứ trong hộp kết hợp thành chuỗi, ví dụ như một vật phẩm của hộp kết hợp là "viên vitamin có thể nhai".?
barlop

11

Giả sử bạn có enum sau

public enum Numbers {Zero = 0, One, Two};

Bạn cần có một cấu trúc để ánh xạ các giá trị đó thành một chuỗi:

public struct EntityName
{
    public Numbers _num;
    public string _caption;

    public EntityName(Numbers type, string caption)
    {
        _num = type;
        _caption = caption;
    }

    public Numbers GetNumber() 
    {
        return _num;
    }

    public override string ToString()
    {
        return _caption;
    }
}

Bây giờ trả về một mảng các đối tượng với tất cả các enums được ánh xạ thành một chuỗi:

public object[] GetNumberNameRange()
{
    return new object[]
    {
        new EntityName(Number.Zero, "Zero is chosen"),
        new EntityName(Number.One, "One is chosen"),
        new EntityName(Number.Two, "Two is chosen")
    };
}

Và sử dụng phần sau để điền vào hộp kết hợp của bạn:

ComboBox numberCB = new ComboBox();
numberCB.Items.AddRange(GetNumberNameRange());

Tạo một hàm để truy xuất kiểu enum trong trường hợp bạn muốn chuyển nó cho một hàm

public Numbers GetConversionType() 
{
    EntityName type = (EntityName)numberComboBox.SelectedItem;
    return type.GetNumber();           
}

và sau đó bạn sẽ ổn :)


+1 giải pháp hay. Gần đây đã gặp vấn đề này và được giải quyết theo cách tương tự (chỉ với một Tuplethay thế). Tôi sẽ biến cả giá trị enum và mô tả thành thuộc tính, sau đó thêm dấu numberCB.DisplayProperty = "Caption"; `và numberCB.ValueProperty = "Num"để bạn có thể sử dụng SelectedValuetrực tiếp và liên kết với nó.
Alejandro

IMHO, có thể là mã nguồn mẫu hoàn chỉnh hơn, nếu cũng có chức năng như Thêm tùy chọn “Tất cả” / “Chọn tất cả” vào ComboBox được sử dụng để lọc tất cả các hàng trong tìm kiếm.
Kiquenet

5

Thử cái này:

// fill list
MyEnumDropDownList.DataSource = Enum.GetValues(typeof(MyEnum));

// binding
MyEnumDropDownList.DataBindings.Add(new Binding("SelectedValue", StoreObject, "StoreObjectMyEnumField"));

StoreObject là ví dụ đối tượng của tôi với thuộc tính StoreObjectMyEnumField cho giá trị MyEnum lưu trữ.


1
Đây là cách tiếp cận tốt nhất cho đến nay nhưng hiện tại, nó không hiệu quả với tôi. Tôi phải sử dụng "SelectedItem" thay vì "SelectedValue"
Tiago Freitas Leal

4
 public static void FillByEnumOrderByNumber<TEnum>(this System.Windows.Forms.ListControl ctrl, TEnum enum1, bool showValueInDisplay = true) where TEnum : struct
    {
        if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj");

        var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum))
                     select
                        new
                         KeyValuePair<TEnum, string>(   (enumValue), enumValue.ToString());

        ctrl.DataSource = values
            .OrderBy(x => x.Key)

            .ToList();

        ctrl.DisplayMember = "Value";
        ctrl.ValueMember = "Key";

        ctrl.SelectedValue = enum1;
    }
    public static void  FillByEnumOrderByName<TEnum>(this System.Windows.Forms.ListControl ctrl, TEnum enum1, bool showValueInDisplay = true  ) where TEnum : struct
    {
        if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj");

        var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum))
                     select 
                        new 
                         KeyValuePair<TEnum,string> ( (enumValue),  enumValue.ToString()  );

        ctrl.DataSource = values
            .OrderBy(x=>x.Value)
            .ToList();

        ctrl.DisplayMember = "Value";
        ctrl.ValueMember = "Key";

        ctrl.SelectedValue = enum1;
    }

Ý anh là gì ? Tôi không hiểu bình luận của bạn. phương pháp mở rộng này hoạt động
Mickey Perlstein

Điều đó phụ thuộc vào việc số enum của bạn có cho phép HOẶC FLags hay không. nếu vậy Bạn có thể thêm một cờ 255 được gọi là Tất cả và gọi hàm với Tất cả là enum1, hàm này tạo mặc định. tức là comboBox1.FillByEnumOrderByName (MyEnum.All)
Mickey Perlstein

Bất kỳ tùy chọn nào như sau: var l = values.OrderBy (x => x.Value) .ToList (); l.Insert (0, "Tất cả");
Kiquenet

enum của tôi là enum A {duck = 0, swan = 1, joker = 3}; hệ thống của bạn sẽ không hoạt động cho tình huống của tôi.
Mickey Perlstein

3

đây là giải pháp để tải item của enum trong combobox:

comboBox1.Items.AddRange( Enum.GetNames(typeof(Border3DStyle)));

Và sau đó sử dụng mục enum dưới dạng văn bản:

toolStripStatusLabel1.BorderStyle = (Border3DStyle)Enum.Parse(typeof(Border3DStyle),comboBox1.Text);

3

Dựa trên câu trả lời từ @Amir Shenouda, tôi kết thúc với điều này:

Định nghĩa của Enum:

public enum Status { Active = 0, Canceled = 3 }; 

Đặt các giá trị thả xuống từ nó:

cbStatus.DataSource = Enum.GetValues(typeof(Status));

Lấy enum từ mục đã chọn:

Status? status = cbStatus.SelectedValue as Status?;

2
tại sao sử dụng nullable? Bạn có thể sử dụng đúc rõ ràng (ngoặc đúc) và không sử dụng nullable
John Demetriou

2
public Form1()
{
    InitializeComponent();
    comboBox.DataSource = EnumWithName<SearchType>.ParseEnum();
    comboBox.DisplayMember = "Name";
}

public class EnumWithName<T>
{
    public string Name { get; set; }
    public T Value { get; set; }

    public static EnumWithName<T>[] ParseEnum()
    {
        List<EnumWithName<T>> list = new List<EnumWithName<T>>();

        foreach (object o in Enum.GetValues(typeof(T)))
        {
            list.Add(new EnumWithName<T>
            {
                Name = Enum.GetName(typeof(T), o).Replace('_', ' '),
                Value = (T)o
            });
        }

        return list.ToArray();
    }
}

public enum SearchType
{
    Value_1,
    Value_2
}

IMHO, có thể là mã nguồn mẫu hoàn chỉnh hơn, nếu cũng có chức năng như Thêm tùy chọn “Tất cả” / “Chọn tất cả” vào ComboBox được sử dụng để lọc tất cả các hàng trong tìm kiếm.
Kiquenet,


1

Tôi sử dụng phương pháp trợ giúp sau mà bạn có thể liên kết với danh sách của mình.

    ''' <summary>
    ''' Returns enumeration as a sortable list.
    ''' </summary>
    ''' <param name="t">GetType(some enumeration)</param>
    Public Shared Function GetEnumAsList(ByVal t As Type) As SortedList(Of String, Integer)

        If Not t.IsEnum Then
            Throw New ArgumentException("Type is not an enumeration.")
        End If

        Dim items As New SortedList(Of String, Integer)
        Dim enumValues As Integer() = [Enum].GetValues(t)
        Dim enumNames As String() = [Enum].GetNames(t)

        For i As Integer = 0 To enumValues.GetUpperBound(0)
            items.Add(enumNames(i), enumValues(i))
        Next

        Return items

    End Function

1

Chuyển đổi enum thành danh sách chuỗi và thêm chuỗi này vào comboBox

comboBox1.DataSource = Enum.GetValues(typeof(SomeEnum)).Cast<SomeEnum>();

Đặt giá trị được hiển thị bằng lựa chọn mục

comboBox1.SelectedItem = SomeEnum.SomeValue;

1

Không có cái nào trong số này hiệu quả với tôi, nhưng cái này đã làm (và nó có thêm lợi ích là có thể mô tả tốt hơn cho tên của từng enum). Tôi không chắc có phải do cập nhật .net hay không, nhưng bất kể tôi nghĩ đây là cách tốt nhất. Bạn sẽ cần thêm tham chiếu đến:

sử dụng System.ComponentModel;

enum MyEnum
{
    [Description("Red Color")]
    Red = 10,
    [Description("Blue Color")]
    Blue = 50
}

....

    private void LoadCombobox()
    {
        cmbxNewBox.DataSource = Enum.GetValues(typeof(MyEnum))
            .Cast<Enum>()
            .Select(value => new
            {
                (Attribute.GetCustomAttribute(value.GetType().GetField(value.ToString()), typeof(DescriptionAttribute)) as DescriptionAttribute).Description,
                value
            })
            .OrderBy(item => item.value)
            .ToList();
        cmbxNewBox.DisplayMember = "Description";
        cmbxNewBox.ValueMember = "value";
    }

Sau đó, khi bạn muốn truy cập dữ liệu, hãy sử dụng hai dòng sau:

        Enum.TryParse<MyEnum>(cmbxNewBox.SelectedValue.ToString(), out MyEnum proc);
        int nValue = (int)proc;

1

Điều này có lẽ sẽ không bao giờ được nhìn thấy trong số tất cả các phản hồi khác, nhưng đây là mã tôi đã nghĩ ra, điều này có lợi khi sử dụng DescriptionAttributenếu nó tồn tại, nhưng nếu không thì sử dụng tên của chính giá trị enum.

Tôi đã sử dụng từ điển vì nó có mẫu mục khóa / giá trị được tạo sẵn. A List<KeyValuePair<string,object>>cũng sẽ hoạt động và không có hàm băm không cần thiết, nhưng một từ điển giúp tạo mã sạch hơn.

Tôi nhận được các thành viên có một MemberTypesố Fieldvà có chữ. Điều này tạo ra một chuỗi chỉ gồm các thành viên là các giá trị enum. Điều này rất mạnh vì một enum không thể có các trường khác.

public static class ControlExtensions
{
    public static void BindToEnum<TEnum>(this ComboBox comboBox)
    {
        var enumType = typeof(TEnum);

        var fields = enumType.GetMembers()
                              .OfType<FieldInfo>()
                              .Where(p => p.MemberType == MemberTypes.Field)
                              .Where(p => p.IsLiteral)
                              .ToList();

        var valuesByName = new Dictionary<string, object>();

        foreach (var field in fields)
        {
            var descriptionAttribute = field.GetCustomAttribute(typeof(DescriptionAttribute), false) as DescriptionAttribute;

            var value = (int)field.GetValue(null);
            var description = string.Empty;

            if (!string.IsNullOrEmpty(descriptionAttribute?.Description))
            {
                description = descriptionAttribute.Description;
            }
            else
            {
                description = field.Name;
            }

            valuesByName[description] = value;
        }

        comboBox.DataSource = valuesByName.ToList();
        comboBox.DisplayMember = "Key";
        comboBox.ValueMember = "Value";
    }


}

0
comboBox1.SelectedItem = MyEnum.Something;

sẽ hoạt động tốt ... Làm thế nào bạn có thể nói rằng đó SelectedItemlà null?


Tôi có thể kiểm tra nó trong trình gỡ lỗi. Tôi cho rằng đó là vì kiểu của SelectedItem là đối tượng, tức là kiểu tham chiếu, và enums là kiểu giá trị. Mặc dù tôi đã mong đợi trình biên dịch nắm bắt được điều đó.

0

Bạn có thể sử dụng các chức năng "FindString ..":

Public Class Form1
    Public Enum Test
        pete
        jack
        fran
        bill
    End Enum
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ComboBox1.DataSource = [Enum].GetValues(GetType(Test))
        ComboBox1.SelectedIndex = ComboBox1.FindStringExact("jack")
        ComboBox1.SelectedIndex = ComboBox1.FindStringExact(Test.jack.ToString())
        ComboBox1.SelectedIndex = ComboBox1.FindStringExact([Enum].GetName(GetType(Test), Test.jack))
        ComboBox1.SelectedItem = Test.bill
    End Sub
End Class

0

Bạn có thể sử dụng danh sách các giá trị KeyValuePair làm nguồn dữ liệu cho hộp tổ hợp. Bạn sẽ cần một phương thức trợ giúp nơi bạn có thể chỉ định kiểu enum và nó trả về IEnumerable> trong đó int là giá trị của enum và string là tên của giá trị enum. Trong hộp kết hợp của bạn, hãy đặt, thuộc tính DisplayMember thành 'Khóa' và thuộc tính ValueMember thành 'Giá trị'. Giá trị và Khóa là thuộc tính công khai của cấu trúc KeyValuePair. Sau đó, khi bạn đặt thuộc tính SelectedItem thành một giá trị enum như bạn đang làm, nó sẽ hoạt động.


0

Hiện tại tôi đang sử dụng thuộc tính Items thay vì DataSource, điều đó có nghĩa là tôi phải gọi Add cho mỗi giá trị enum, nhưng nó là một enum nhỏ và dù sao thì cũng là mã tạm thời của nó.

Sau đó, tôi chỉ có thể thực hiện Convert.ToInt32 trên giá trị và đặt nó bằng SelectedIndex.

Giải pháp tạm thời, nhưng YAGNI cho bây giờ.

Chúc mừng các ý tưởng, tôi có thể sẽ sử dụng chúng khi tôi thực hiện phiên bản phù hợp sau khi nhận được một loạt phản hồi của khách hàng.



0
comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));

comboBox1.SelectedIndex = (int)MyEnum.Something;

comboBox1.SelectedIndex = Convert.ToInt32(MyEnum.Something);

Cả hai đều làm việc cho tôi, bạn có chắc là không có điều gì khác sai?


2
Không chắc chắn điều này sẽ làm việc nếu sử dụng các giá trị enum tùy chỉnh, ví dụ:enum MyEnum { Something = 47 }
Samantha Branham

0

Phương pháp chung để đặt enum làm nguồn dữ liệu cho trình đơn thả xuống

Hiển thị sẽ là tên. Giá trị được chọn sẽ là chính Enum

public IList<KeyValuePair<string, T>> GetDataSourceFromEnum<T>() where T : struct,IConvertible
    {
        IList<KeyValuePair<string, T>> list = new BindingList<KeyValuePair<string, T>>();
        foreach (string value in Enum.GetNames(typeof(T)))
        {
            list.Add(new KeyValuePair<string, T>(value, (T)Enum.Parse(typeof(T), value)));
        }
        return list;
    }

0

Đó luôn là một vấn đề. nếu bạn có một Enum được sắp xếp, như từ 0 đến ...

public enum Test
      one
      Two
      Three
 End

bạn có thể liên kết tên với combobox và thay vì sử dụng thuộc .SelectedValuetính.SelectedIndex

   Combobox.DataSource = System.Enum.GetNames(GetType(test))

Dim x as byte = 0
Combobox.Selectedindex=x

0

Trong Framework 4, bạn có thể sử dụng mã sau:

Để liên kết enum MultiColumnMode với combobox, ví dụ:

cbMultiColumnMode.Properties.Items.AddRange(typeof(MultiColumnMode).GetEnumNames());

và để lấy chỉ mục đã chọn:

MultiColumnMode multiColMode = (MultiColumnMode)cbMultiColumnMode.SelectedIndex;

lưu ý: Tôi sử dụng combobox DevExpress trong ví dụ này, bạn có thể làm tương tự trong Win Form Combobox


0

Đến bữa tiệc này hơi muộn,

Phương thức SelectedValue.ToString () sẽ kéo vào DisplayedName. Tuy nhiên, bài viết này DataBinding Enum và cả With Des Description chỉ ra một cách hữu ích để không chỉ có điều đó mà thay vào đó bạn có thể thêm một thuộc tính mô tả tùy chỉnh vào enum và sử dụng nó cho giá trị hiển thị của bạn nếu bạn muốn. Rất đơn giản và dễ dàng và khoảng 15 dòng mã (trừ khi bạn đếm dấu ngoặc nhọn) cho mọi thứ.

Nó là một đoạn mã khá tiện lợi và bạn có thể biến nó thành một phương thức mở rộng để khởi động ...


0

chỉ sử dụng truyền theo cách này:

if((YouEnum)ComboBoxControl.SelectedItem == YouEnum.Español)
{
   //TODO: type you code here
}

0

Bạn có thể sử dụng một phương pháp mở rộng

 public static void EnumForComboBox(this ComboBox comboBox, Type enumType)
 {
     var memInfo = enumType.GetMembers().Where(a => a.MemberType == MemberTypes.Field).ToList();
     comboBox.Items.Clear();
     foreach (var member in memInfo)
     {
         var myAttributes = member.GetCustomAttribute(typeof(DescriptionAttribute), false);
         var description = (DescriptionAttribute)myAttributes;
         if (description != null)
         {
             if (!string.IsNullOrEmpty(description.Description))
             {
                 comboBox.Items.Add(description.Description);
                 comboBox.SelectedIndex = 0;
                 comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
             }
         }   
     }
 }

Cách sử dụng ... Khai báo enum

using System.ComponentModel;

public enum CalculationType
{
    [Desciption("LoaderGroup")]
    LoaderGroup,
    [Description("LadingValue")]
    LadingValue,
    [Description("PerBill")]
    PerBill
}

Phương pháp này hiển thị mô tả trong các mục hộp Tổ hợp

combobox1.EnumForComboBox(typeof(CalculationType));

0

Điều này đã làm việc cho tôi:

comboBox1.DataSource = Enum.GetValues(typeof(MyEnum));
comboBox1.SelectedIndex = comboBox1.FindStringExact(MyEnum.something.ToString());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.