как связать enum с элементом управления dropdownlist в asp.net?

<p>допустим, у меня есть следующее простое перечисление:</p><pre><code>enum response { yes = 1, no = 2, maybe = 3 } </code></pre><p>как можно связать это перечисление с элементом управления dropdownlist, чтобы описания отображались в списке, а также извлекали соответствующее числовое значение (1,2,3) после выбора параметра?</p>

<p>я, вероятно, не буду <strong>связывать</strong> данные, так как они перечисляются, и они не изменятся после компиляции (если у меня не будет одного из этих <em> stoopid </em> моменты).</p><p>лучше просто перебрать перечисление:</p><pre><code>dim itemvalues as array = system.enum.getvalues(gettype(response)) dim itemnames as array = system.enum.getnames(gettype(response)) for i as integer = 0 to itemnames.length - 1 dim item as new listitem(itemnames(i), itemvalues(i)) dropdownlist.items.add(item) next </code></pre><p>или то же самое в c #</p><pre><code>array itemvalues = system.enum.getvalues(typeof(response)); array itemnames = system.enum.getnames(typeof(response)); for (int i = 0; i <= itemnames.length - 1 ; i++) { listitem item = new listitem(itemnames[i], itemvalues[i]); dropdownlist.items.add(item); } </code></pre>

<p>используйте следующий служебный класс <code>enumeration</code> для получения <code>idictionary<int,string></code> (enum value & name name) из <strong>enumeration</strong>; затем вы связываете <strong>idictionary</strong> с привязываемым элементом управления.</p><pre><code>public static class enumeration { public static idictionary<int, string> getall<tenum>() where tenum: struct { var enumerationtype = typeof (tenum); if (!enumerationtype.isenum) throw new argumentexception("enumeration type is expected."); var dictionary = new dictionary<int, string>(); foreach (int value in enum.getvalues(enumerationtype)) { var name = enum.getname(enumerationtype, value); dictionary.add(value, name); } return dictionary; } } </code></pre><p><strong>пример:</strong> использование служебного класса для привязки данных перечисления к элементу управления</p><pre><code>ddlresponse.datasource = enumeration.getall<response>(); ddlresponse.datatextfield = "value"; ddlresponse.datavaluefield = "key"; ddlresponse.databind(); </code></pre>

<p>я использую это для <strong>asp.net mvc</strong>:</p><pre><code>html.dropdownlistfor(o => o.enumproperty, enum.getvalues(typeof(enumtype)).cast<enumtype>().select(x => new selectlistitem { text = x.tostring(), value = ((int)x).tostring() })) </code></pre>

<p>моя версия - просто сжатая форма вышеупомянутого:</p><pre><code>foreach (response r in enum.getvalues(typeof(response))) { listitem item = new listitem(enum.getname(typeof(response), r), r.tostring()); dropdownlist1.items.add(item); } </code></pre>

<pre><code>public enum color { red, green, blue } </code></pre><p>каждый тип enum происходит от system.enum. есть два статических метода, которые помогают привязать данные к элементу управления раскрывающегося списка (и получить значение). это enum.getnames и enum.parse. используя getnames, вы можете привязать свой элемент управления выпадающего списка следующим образом:</p><pre><code>protected system.web.ui.webcontrols.dropdownlist ddcolor; private void page\_load(object sender, system.eventargs e) { if(!ispostback) { ddcolor.datasource = enum.getnames(typeof(color)); ddcolor.databind(); } } </code></pre><p>теперь, если вам нужно значение enum back on selection ....</p><pre><code> private void ddcolor\_selectedindexchanged(object sender, system.eventargs e) { color selectedcolor = (color)enum.parse(typeof(color),ddcolor.selectedvalue } </code></pre>

<p>после прочтения всех постов я предложил комплексное решение для поддержки отображения описания перечисления в раскрывающемся списке, а также выбора правильного значения в раскрывающемся списке модель при отображении в режиме редактирования:</p><p>перечисление:</p><pre><code>using system.componentmodel; public enum companytype { [description("")] null = 1, [description("supplier")] supplier = 2, [description("customer")] customer = 3 } </code></pre><p>класс расширения enum:</p><pre><code>using system.collections.generic; using system.componentmodel; using system.linq; using system.web.mvc; public static class enumextension { public static string todescription(this system.enum value) { var attributes = (descriptionattribute[])value.gettype().getfield(value.tostring()).getcustomattributes(typeof(descriptionattribute), false); return attributes.length > 0 ? attributes[0].description : value.tostring(); } public static ienumerable<selectlistitem> toselectlist<t>(this system.enum enumvalue) { return system.enum.getvalues(enumvalue.gettype()).cast<t>() .select( x => new selectlistitem { text = ((system.enum)(object) x).todescription(), value = x.tostring(), selected = (enumvalue.equals(x)) }); } } </code></pre><p>модельный класс:</p><pre><code>public class company { public string companyname { get; set; } public companytype type { get; set; } } </code></pre><p>и просмотр:</p><pre><code>@html.dropdownlistfor(m => m.type, @model.type.toselectlist<companytype>()) </code></pre><p>и если вы используете этот раскрывающийся список без привязки к модели, вы можете использовать вместо этого:</p><pre><code>@html.dropdownlist("type", enum.getvalues(typeof(companytype)).cast<companytype>() .select(x => new selectlistitem {text = x.todescription(), value = x.tostring()})) </code></pre><p>таким образом, вы можете ожидать, что ваш выпадающий список отображает описание вместо значений перечисления. также, когда дело доходит до редактирования, ваша модель будет обновляться по выпадающему выбору значения после публикации страницы.</p>

<p>как уже говорили другие - не привязывайте данные к перечислению, если вам не нужно привязывать разные перечисления в зависимости от ситуации. есть несколько способов сделать это, пара примеров ниже.</p><p><strong>objectdatasource</strong></p><p>декларативный способ сделать это с objectdatasource. сначала создайте класс businessobject, который будет возвращать list для привязки dropdownlist к:</p><pre><code>public class dropdowndata { enum responses { yes = 1, no = 2, maybe = 3 } public string text { get; set; } public int value { get; set; } public list<dropdowndata> getlist() { var items = new list<dropdowndata>(); foreach (int value in enum.getvalues(typeof(responses))) { items.add(new dropdowndata { text = enum.getname(typeof (responses), value), value = value }); } return items; } } </code></pre><p>затем добавьте html-разметку на страницу aspx, чтобы указать на этот класс bo:</p><pre><code><asp:dropdownlist id="dropdownlist1" runat="server" datasourceid="objectdatasource1" datatextfield="text" datavaluefield="value"> </asp:dropdownlist> <asp:objectdatasource id="objectdatasource1" runat="server" selectmethod="getlist" typename="dropdowndata"></asp:objectdatasource> </code></pre><p>эта опция не требует кода позади.</p><p><strong>код позади databind</strong></p><p>чтобы свернуть html-код на странице aspx и выполнить связывание в code behind:</p><pre><code>enum responses { yes = 1, no = 2, maybe = 3 } protected void page\_load(object sender, eventargs e) { if (!ispostback) { foreach (int value in enum.getvalues(typeof(responses))) { dropdownlist1.items.add(new listitem(enum.getname(typeof(responses), value), value.tostring())); } } } </code></pre><p>в любом случае, хитрость заключается в том, чтобы позволить типам enum методов getvalues, getnames и т.д. работать за вас.</p>

<p>я не уверен, как это сделать в asp.net, но посмотрите <a href="https://stackoverflow.com/questions/58743/databinding-an-enum-property-to-a-combobox-in-wpf#58819">this</a> post ... это может помочь?</p><pre><code>enum.getvalues(typeof(response)); </code></pre>

<pre><code>array itemvalues = enum.getvalues(typeof(taskstatus)); array itemnames = enum.getnames(typeof(taskstatus)); for (int i = 0; i <= itemnames.length; i++) { listitem item = new listitem(itemnames.getvalue(i).tostring(), itemvalues.getvalue(i).tostring()); ddlstatus.items.add(item); } </code></pre>

<p>вы можете использовать linq:</p><pre><code>var responsetypes= enum.getnames(typeof(response)).select(x => new { text = x, value = (int)enum.parse(typeof(response), x) }); dropdownlist.datasource = responsetypes; dropdownlist.datatextfield = "text"; dropdownlist.datavaluefield = "value"; dropdownlist.databind(); </code></pre>

<pre><code>public enum color { red, green, blue } ddcolor.datasource = enum.getnames(typeof(color)); ddcolor.databind(); </code></pre>

<p>после нахождения этого ответа я придумал, как мне кажется, лучший (по крайней мере, более элегантный) способ сделать это, подумал, что вернусь и поделюсь этим здесь.</p><p>page\_load:</p><pre><code>dropdownlist1.datasource = enum.getvalues(typeof(response)); dropdownlist1.databind(); </code></pre><p>loadvalues:</p><pre><code>response rin = response.maybe; dropdownlist1.text = rin.tostring(); </code></pre><p>savevalues:</p><pre><code>response rout = (response) enum.parse(typeof(response), dropdownlist1.text); </code></pre>

<p>общий код с использованием ответа шесть.</p><pre><code>public static void bindcontroltoenum(databoundcontrol controltobind, type type) { //listcontrol if (type == null) throw new argumentnullexception("type"); else if (controltobind==null ) throw new argumentnullexception("controltobind"); if (!type.isenum) throw new argumentexception("only enumeration type is expected."); dictionary<int, string> pairs = new dictionary<int, string>(); foreach (int i in enum.getvalues(type)) { pairs.add(i, enum.getname(type, i)); } controltobind.datasource = pairs; listcontrol lstcontrol = controltobind as listcontrol; if (lstcontrol != null) { lstcontrol.datatextfield = "value"; lstcontrol.datavaluefield = "key"; } controltobind.databind(); } </code></pre>

<p>это не совсем то, что вы ищете, но может помочь:</p><p> <a href="http://blog.jeffhandley.com/archive/2008/01/27/enum-list-dropdown-control.aspx">http://blog.jeffhandley.com/archive/2008/01/27/enum-list-dropdown-control.aspx</a> </p>

<p>это, наверное, старый вопрос ... но так я и сделал.</p><p>модель:</p><pre><code>public class yourentity { public int id { get; set; } public string name{ get; set; } public string description { get; set; } public optiontype types { get; set; } } public enum optiontype { unknown, option1, option2, option3 } </code></pre><p>затем в представлении: вот как использовать заполнить раскрывающийся список.</p><pre><code>@html.enumdropdownlistfor(model => model.types, htmlattributes: new { @class = "form-control" }) </code></pre><p>это должно заполнить все в вашем списке enum. надеюсь это поможет..</p>

<p>с тех пор asp.net был дополнен некоторыми дополнительными функциями, и теперь вы можете использовать встроенное перечисление для раскрывающегося списка.</p><p>если вы хотите привязать сам enum, используйте это:</p><pre><code>@html.dropdownlist("response", enumhelper.getselectlist(typeof(response))) </code></pre><p>если вы привязываетесь к экземпляру response, используйте это:</p><pre><code>// assuming model.response is an instance of response @html.enumdropdownlistfor(m => m.response) </code></pre>

<p>почему бы не использовать вот так, чтобы можно было передавать каждый listcontrole:</p><pre><code> public static void bindtoenum(type enumtype, listcontrol lc) { // get the names from the enumeration string[] names = enum.getnames(enumtype); // get the values from the enumeration array values = enum.getvalues(enumtype); // turn it into a hash table hashtable ht = new hashtable(); for (int i = 0; i < names.length; i++) // note the cast to integer here is important // otherwise we'll just get the enum string back again ht.add(names[i], (int)values.getvalue(i)); // return the dictionary to be bound to lc.datasource = ht; lc.datatextfield = "key"; lc.datavaluefield = "value"; lc.databind(); } </code></pre><pre><code> bindtoenum(typeof(newstype), dropdownlist1); bindtoenum(typeof(newstype), checkboxlist1); bindtoenum(typeof(newstype), radobuuttonlist1); </code></pre>

<p>если вы хотите иметь более удобное для пользователя описание в поле со списком (или другим элементом управления), вы можете использовать атрибут description со следующей функцией:</p><pre><code> public static object getenumdescriptions(type enumtype) { var list = new list<keyvaluepair<enum, string>>(); foreach (enum value in enum.getvalues(enumtype)) { string description = value.tostring(); fieldinfo fieldinfo = value.gettype().getfield(description); var attribute = fieldinfo.getcustomattributes(typeof(descriptionattribute), false).first(); if (attribute != null) { description = (attribute as descriptionattribute).description; } list.add(new keyvaluepair<enum, string>(value, description)); } return list; } </code></pre><p>вот пример перечисления с примененными атрибутами description:</p><pre><code> enum sampleenum { normalnospaces, [description("description with spaces")] descriptionwithspaces, [description("50%")] percent\_50, } </code></pre><p>тогда привязывайся к контролю вот так ...</p><pre><code> m\_combo\_sample.datasource = getenumdescriptions(typeof(sampleenum)); m\_combo\_sample.displaymember = "value"; m\_combo\_sample.valuemember = "key"; </code></pre><p>таким образом, вы можете поместить любой текст в раскрывающемся списке без необходимости выглядеть как имя переменной</p>

<p>как asp.net, так и учебник winforms с выпадающим списком и выпадающим списком: <a href="http://www.docstorus.com/viewer.aspx?code=833d27e2-5e3b-4ec0-b950-02c8fc2ec572&title=how%20to%20use%20enum%20with%20combobox%20in%20c#%20winforms%20and%20asp.net">как использовать enum с выпадающим списком в c # winforms и asp.net</a> </p><p>надежда помогает</p>

<p>прочтите мой пост о создании пользовательского помощника "asp.net mvc - создание помощника dropdownlist для перечислений": <a href="http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx">http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp -сетью-mvc-создание-а-dropdownlist-хелпер-для-enums.aspx</a> </p>

<p>это мое решение для заказа выпадающего списка enum и databind (текст и значение) с помощью linq</p><pre><code>var mylist = enum.getvalues(typeof(myenum)).cast<myenum>().tolist<myenum>().orderby(l => l.tostring()); foreach (myenum item in mylist) ddldivisao.items.add(new listitem(item.tostring(), ((int)item).tostring())); </code></pre>

<p>принятое решение не работает, но приведенный ниже код поможет другим, ищущим самое короткое решение.</p><pre><code> foreach (string value in enum.getnames(typeof(response))) ddlresponse.items.add(new listitem() { text = value, value = ((int)enum.parse(typeof(response), value)).tostring() }); </code></pre>

<p>вы также можете использовать методы расширения. для тех, кто не знаком с расширениями, я предлагаю проверить документацию <a href="http://msdn.microsoft.com/en-us/library/bb384936.aspx">vb</a> и <a href="http://msdn.microsoft.com/en-us/library/bb383977.aspx">c #</a> .</p><hr><p>расширение vb:</p><pre><code>namespace customextensions public module listitemcollectionextension <runtime.compilerservices.extension()> \_ public sub addenum(of tenum as structure)(items as system.web.ui.webcontrols.listitemcollection) dim enumerationtype as system.type = gettype(tenum) dim enumundertype as system.type = system.enum.getunderlyingtype(enumtype) if not enumerationtype.isenum then throw new argumentexception("enumeration type is expected.") dim enumtypenames() as string = system.enum.getnames(enumerationtype) dim enumtypevalues() as tenum = system.enum.getvalues(enumerationtype) for i = 0 to enumtypenames.length - 1 items.add(new system.web.ui.webcontrols.listitem(saveresponsetypenames(i), trycast(enumtypevalues(i), system.enum).tostring("d"))) next end sub end module end namespace </code></pre><p>чтобы использовать расширение:</p><pre><code>imports <projectname>.customextensions.listitemcollectionextension ... yourdropdownlist.items.addenum(of enumtype)() </code></pre><hr><p>расширение c #:</p><pre><code>namespace customextensions { public static class listitemcollectionextension { public static void addenum<tenum>(this system.web.ui.webcontrols.listitemcollection items) where tenum : struct { system.type enumtype = typeof(tenum); system.type enumundertype = system.enum.getunderlyingtype(enumtype); if (!enumtype.isenum) throw new exception("enumeration type is expected."); string[] enumtypenames = system.enum.getnames(enumtype); tenum[] enumtypevalues = (tenum[])system.enum.getvalues(enumtype); for (int i = 0; i < enumtypevalues.length; i++) { items.add(new system.web.ui.webcontrols.listitem(enumtypenames[i], (enumtypevalues[i] as system.enum).tostring("d"))); } } } } </code></pre><p>чтобы использовать расширение:</p><pre><code>using customextensions.listitemcollectionextension; ... yourdropdownlist.items.addenum<enumtype>() </code></pre><hr><p>если вы хотите установить выбранный элемент одновременно, замените</p><pre><code>items.add(new system.web.ui.webcontrols.listitem(saveresponsetypenames(i), saveresponsetypevalues(i).tostring("d"))) </code></pre><p>с</p><pre><code>dim newlistitem as system.web.ui.webcontrols.listitem newlistitem = new system.web.ui.webcontrols.listitem(enumtypenames(i), convert.changetype(enumtypevalues(i), enumundertype).tostring()) newlistitem.selected = if(equalitycomparer(of tenum).default.equals(selected, saveresponsetypevalues(i)), true, false) items.add(newlistitem) </code></pre><p>преобразование в system.enum позволяет избежать проблем с размером int и выходными данными. например, 0xffff0000 будет 4294901760 как uint, но будет -65536 как int.</p><p>trycast и system.enum немного быстрее, чем convert.changetype (enumtypevalues [i], enumundertype) .tostring () (12:13 в моих тестах скорости).</p>