MVC3 มีดโกน DropDownListFor Enums


84

กำลังพยายามอัปเดตโครงการของฉันเป็น MVC3 สิ่งที่ฉันไม่พบ:

ฉันมีประเภทข้อมูลง่ายๆของ ENUMS:

public enum States()
{
  AL,AK,AZ,...WY
}

ซึ่งฉันต้องการใช้เป็น DropDown / SelectList ในมุมมองของโมเดลที่มีประเภทข้อมูลนี้:

public class FormModel()
{
    public States State {get; set;}
}

ค่อนข้างตรงไปตรงมา: เมื่อฉันไปใช้มุมมองสร้างอัตโนมัติสำหรับคลาสบางส่วนนี้จะไม่สนใจประเภทนี้

ฉันต้องการรายการเลือกแบบง่ายที่กำหนดค่าของ enum เป็นรายการที่เลือกเมื่อฉันกดส่งและประมวลผลผ่านวิธี AJAX - JSON POST ของฉัน

และมากกว่ามุมมอง (???!):

    <div class="editor-field">
        @Html.DropDownListFor(model => model.State, model => model.States)
    </div>

ขอบคุณล่วงหน้าสำหรับคำแนะนำ!


8
สำหรับใครก็ตามที่เจอเธรดนี้และใช้ MVC 5.1 ขึ้นไปวิธีการช่วยเหลือ @ Html.EnumDropDownListFor () ถูกสร้างขึ้นใน MVC แล้ว - โปรดดูที่asp.net/mvc/overview/releases/mvc51-release-notes
mecsco

คำตอบ:


55

ฉันเพิ่งทำโครงการของตัวเอง โค้ดด้านล่างนี้เป็นส่วนหนึ่งของคลาสตัวช่วยของฉันฉันหวังว่าฉันจะมีทุกวิธีที่จำเป็น เขียนความคิดเห็นหากไม่ได้ผลเราจะตรวจสอบอีกครั้ง

public static class SelectExtensions
{

    public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
    {
        if (expression.Body.NodeType == ExpressionType.Call)
        {
            MethodCallExpression methodCallExpression = (MethodCallExpression)expression.Body;
            string name = GetInputName(methodCallExpression);
            return name.Substring(expression.Parameters[0].Name.Length + 1);

        }
        return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
    }

    private static string GetInputName(MethodCallExpression expression)
    {
        // p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...
        MethodCallExpression methodCallExpression = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
    {
        string inputName = GetInputName(expression);
        var value = htmlHelper.ViewData.Model == null
            ? default(TProperty)
            : expression.Compile()(htmlHelper.ViewData.Model);

        return htmlHelper.DropDownList(inputName, ToSelectList(typeof(TProperty), value.ToString()));
    }

    public static SelectList ToSelectList(Type enumType, string selectedItem)
    {
        List<SelectListItem> items = new List<SelectListItem>();
        foreach (var item in Enum.GetValues(enumType))
        {
            FieldInfo fi = enumType.GetField(item.ToString());
            var attribute = fi.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();
            var title = attribute == null ? item.ToString() : ((DescriptionAttribute)attribute).Description;
            var listItem = new SelectListItem
                {
                    Value = ((int)item).ToString(),
                    Text = title,
                    Selected = selectedItem == ((int)item).ToString()
                };
            items.Add(listItem);
        }

        return new SelectList(items, "Value", "Text", selectedItem);
    }
}

ใช้เป็น:

Html.EnumDropDownListFor(m => m.YourEnum);

อัปเดต

ฉันได้สร้างตัวช่วย Html ทางเลือกแล้ว สิ่งที่คุณต้องทำเพื่อใช้คือเปลี่ยน baseviewpage ของคุณในviews\web.config.

ด้วยพวกเขาคุณสามารถทำได้:

@Html2.DropDownFor(m => m.YourEnum);
@Html2.CheckboxesFor(m => m.YourEnum);
@Html2.RadioButtonsFor(m => m.YourEnum);

ข้อมูลเพิ่มเติมที่นี่: http://blog.gauffin.org/2011/10/first-draft-of-my-alternative-html-helpers/


1
ใช้ได้ดีทั้งสองวิธีฉันได้รับข้อผิดพลาดในการรวบรวม: บรรทัดที่ 41: ส่งคืน htmlHelper.DropDownList (inputName, ToSelectList (typeof (TProperty), value ToString ())); 'System.Web.Mvc.HtmlHelper <TModel>' ไม่มีคำจำกัดความสำหรับ 'DropDownList' และไม่มีวิธีการขยาย 'DropDownList' ที่ยอมรับอาร์กิวเมนต์แรกของประเภท 'System.Web.Mvc.HtmlHelper <TModel>' สามารถพบได้ ( คุณขาดการใช้คำสั่งหรือการอ้างอิงการประกอบหรือไม่)
jordan.baucke

1
@jordan ฉันมีข้อผิดพลาดเดียวกัน คุณจัดการเพื่อแก้ไขปัญหาหรือไม่
SF Developer

9
@filu @jordan เพิ่มusing System.Web.Mvc.Html;ตามที่คุณต้องการเพื่อเข้าถึงSelectExtensionsClass
Simon Hartcher

3
@Para ฉันได้รับปัญหาเดียวกันค่าที่เลือกไม่ปรากฏที่เลือกในมุมมอง (ฉันต้องเปลี่ยน((int)item).ToString()เพื่อEnum.GetName(enumType, item)ให้ได้รับการSelectListItemบันทึกอย่างถูกต้องตามที่เลือก แต่ก็ยังใช้ไม่ได้)
Fernando Neira

1
เพิ่งเพิ่มคำตอบด้านล่างซึ่งครอบคลุมถึงปัญหาการเลือกซึ่งเกิดจากความเข้าใจผิดเกี่ยวกับพฤติกรรมของ DropDownList ที่มากเกินไป
Jon Egerton

199

ฉันพบวิธีแก้ปัญหาที่ง่ายกว่านี้ที่นี่: http://coding-in.net/asp-net-mvc-3-method-extension/

using System;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace EnumHtmlHelper.Helper
{    
    public static class EnumDropDownList
    {
        public static HtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> modelExpression, string firstElement)
        {
            var typeOfProperty = modelExpression.ReturnType;
            if(!typeOfProperty.IsEnum)
                throw new ArgumentException(string.Format("Type {0} is not an enum", typeOfProperty));     
            var enumValues = new SelectList(Enum.GetValues(typeOfProperty));
            return htmlHelper.DropDownListFor(modelExpression, enumValues, firstElement);
}   }   }

หนึ่งบรรทัดในมีดโกนจะทำ:

@Html.DropDownListFor(model => model.State, new SelectList(Enum.GetValues(typeof(MyNamespace.Enums.States))))

คุณยังสามารถค้นหาโค้ดสำหรับทำด้วยวิธีการขยายในบทความที่เชื่อมโยง


6
ฉันคิดว่าสิ่งนี้ควรถูกทำเครื่องหมายว่าเป็นโซลูชัน สิ่งที่ดีที่สุดไม่ได้ถูกกำหนดโดยความซับซ้อน แต่เป็นความเรียบง่าย
Lord of Scripts

3
สำหรับคนที่ดูเวอร์ชัน DropDowList (เช่นฉัน): @ Html.DropDownList ("listName", SelectList ใหม่ (Enum.GetValues ​​(typeof (MyNamespace.Enums.States)))
dstr

2
@JonEgerton ถ้าคุณหมายถึงเช่นเดียวกับฉันฉันก็เห็นด้วย หากคุณต้องการแสดง enums + description + ภาพที่คุณหลงทางด้วยโซลูชันของ Mike McLaughlin
Elisabeth

1
ปัญหาเดียวที่ฉันพบในการแก้ปัญหานี้คือไม่ได้จับคู่ค่าที่เลือกอย่างถูกต้องเมื่อโหลด นอกเหนือจากนั้นค่อนข้างดี
triangulito

3
@triangulito นี่ไม่ใช่ปัญหาเลย :)@Html.DropDownListFor(model => model.State, new SelectList(Enum.GetValues(typeof(MyNamespace.Enums.States)),model.State))
VladL


17

หากคุณต้องการสิ่งที่เรียบง่ายจริงๆก็มีวิธีอื่นขึ้นอยู่กับว่าคุณจัดเก็บสถานะในฐานข้อมูลอย่างไร

หากคุณมีเอนทิตีเช่นนี้:

public class Address
{
     //other address fields

     //this is what the state gets stored as in the db
     public byte StateCode { get; set; }

     //this maps our db field to an enum
     public States State
     {
         get
         {
             return (States)StateCode;
         }
         set
         {
             StateCode = (byte)value;
         }
     }
}

จากนั้นการสร้างดรอปดาวน์จะทำได้ง่ายดังนี้:

@Html.DropDownListFor(x => x.StateCode,
    from State state in Enum.GetValues(typeof(States))
    select new SelectListItem() { Text = state.ToString(), Value = ((int)state).ToString() }
);

LINQ ไม่สวยเหรอ?


คุณกำหนด States enum- ใน Model หรือ View ไว้ที่ไหน
superartsy

ในโมเดลตามที่คลาสโมเดลใช้
sjmeverett

1
@stewartml เมื่อ ViewModel ของฉันมีคุณสมบัติ enum + "SelectedCodeProperty" แสดงว่านี่เป็นหนึ่งคุณสมบัติที่มากเกินไปในโพสต์ของคุณ ทำไมไม่มี enum ในทั้งสองค่าที่เลือกโพสต์กลับไปที่เซิร์ฟเวอร์ + เป็นค่าไอเท็ม
Elisabeth

13

ฉันสามารถทำสิ่งนี้ได้ในซับเดียว

@Html.DropDownListFor(m=>m.YourModelProperty,new SelectList(Enum.GetValues(typeof(YourEnumType))))

8

จากคำตอบที่ได้รับการยอมรับโดย @jgauffin ฉันได้สร้างเวอร์ชันของตัวเองEnumDropDownListForขึ้นมาซึ่งเกี่ยวข้องกับปัญหาในการเลือกรายการ

ปัญหาที่เกิดขึ้นเป็นรายละเอียดในคำตอบดังนั้นที่นี่อีก : และเป็นพื้นลงไปที่ความเข้าใจผิดของลักษณะการทำงานของ overloads DropDownListที่แตกต่างกันได้

รหัสเต็มของฉัน (ซึ่งรวมถึงการโอเวอร์โหลดhtmlAttributesฯลฯ คือ:

public static class EnumDropDownListForHelper
{

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, null, null);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            object htmlAttributes
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, null, htmlAttributes);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            IDictionary<string, object> htmlAttributes
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, null, htmlAttributes);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            string optionLabel
        ) where TModel : class
    {
        return EnumDropDownListFor<TModel, TProperty>(
                            htmlHelper, expression, optionLabel, null);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            string optionLabel, 
            IDictionary<string,object> htmlAttributes
        ) where TModel : class
    {
        string inputName = GetInputName(expression);
        return htmlHelper.DropDownList(
                            inputName, ToSelectList(typeof(TProperty)), 
                            optionLabel, htmlAttributes);
    }

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TProperty>> expression, 
            string optionLabel, 
            object htmlAttributes
        ) where TModel : class
    {
        string inputName = GetInputName(expression);
        return htmlHelper.DropDownList(
                            inputName, ToSelectList(typeof(TProperty)), 
                            optionLabel, htmlAttributes);
    }


    private static string GetInputName<TModel, TProperty>(
            Expression<Func<TModel, TProperty>> expression)
    {
        if (expression.Body.NodeType == ExpressionType.Call)
        {
            MethodCallExpression methodCallExpression 
                            = (MethodCallExpression)expression.Body;
            string name = GetInputName(methodCallExpression);
            return name.Substring(expression.Parameters[0].Name.Length + 1);

        }
        return expression.Body.ToString()
                    .Substring(expression.Parameters[0].Name.Length + 1);
    }

    private static string GetInputName(MethodCallExpression expression)
    {
        // p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...
        MethodCallExpression methodCallExpression 
                            = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }


    private static SelectList ToSelectList(Type enumType)
    {
        List<SelectListItem> items = new List<SelectListItem>();
        foreach (var item in Enum.GetValues(enumType))
        {
            FieldInfo fi = enumType.GetField(item.ToString());
            var attribute = fi.GetCustomAttributes(
                                       typeof(DescriptionAttribute), true)
                                  .FirstOrDefault();
            var title = attribute == null ? item.ToString() 
                              : ((DescriptionAttribute)attribute).Description;
            var listItem = new SelectListItem
            {
                Value = item.ToString(),
                Text = title,
            };
            items.Add(listItem);
        }

        return new SelectList(items, "Value", "Text");
    }
}

ผมเคยเขียนเรื่องนี้ในบล็อกของฉันที่นี่


1
นี่เป็นทางออกเดียวที่ฉันพบว่าเลือกค่าที่เกี่ยวข้องล่วงหน้าสำหรับการแจงนับของฉันอย่างถูกต้อง ขอบคุณ!
Edwin Groenendaal

น่ากลัว นี่ควรเป็นคำตอบที่ได้รับการยอมรับอย่างแน่นอน - ได้ผล คำตอบที่ยอมรับไม่ได้
neminem

3

สิ่งนี้จะเป็นประโยชน์สำหรับการเลือกค่า int จาก enum: นี่SpecTypeคือintฟิลด์ ... และenmSpecTypeคือenumไฟล์.

@Html.DropDownList(
    "SpecType", 
     YourNameSpace.SelectExtensions.ToSelectList(typeof(NREticaret.Core.Enums.enmSpecType), 
     Model.SpecType.ToString()), "Tip Seçiniz", new 
     { 
         gtbfieldid = "33", 
         @class = "small" 
     })

3

ฉันได้ทำการเปลี่ยนแปลงต่อไปนี้กับวิธี SelectList เพื่อให้มันทำงานได้ดีขึ้นสำหรับฉันเล็กน้อย บางทีมันอาจจะมีประโยชน์สำหรับคนอื่น ๆ

public static SelectList ToSelectList<T>(T selectedItem)
        {
            if (!typeof(T).IsEnum) throw new InvalidEnumArgumentException("The specified type is not an enum");

            var selectedItemName = Enum.GetName(typeof (T), selectedItem);
            var items = new List<SelectListItem>();
            foreach (var item in Enum.GetValues(typeof(T)))
            {
                var fi = typeof(T).GetField(item.ToString());
                var attribute = fi.GetCustomAttributes(typeof(DescriptionAttribute), true).FirstOrDefault();

                var enumName = Enum.GetName(typeof (T), item);
                var title = attribute == null ? enumName : ((DescriptionAttribute)attribute).Description;

                var listItem = new SelectListItem
                {
                    Value = enumName,
                    Text = title,
                    Selected = selectedItemName == enumName
                };
                items.Add(listItem);
            }

            return new SelectList(items, "Value", "Text");
        }

3
    public enum EnumStates
    {
        AL = 0,
        AK = 1,
        AZ = 2,
        WY = 3
    }


@Html.DropDownListFor(model => model.State, (from EnumStates e in Enum.GetValues(typeof(EnumStates))
                                                               select new SelectListItem { Value = ((int)e).ToString(), Text = e.ToString() }), "select", new { @style = "" })
                @Html.ValidationMessageFor(model => model.State)  //With select



//Or


@Html.DropDownListFor(model => model.State, (from EnumStates e in Enum.GetValues(typeof(EnumStates))
                                                               select new SelectListItem { Value = ((int)e).ToString(), Text = e.ToString() }), null, new { @style = "" })
                @Html.ValidationMessageFor(model => model.State)   //With out select

คุณกำหนด EnumState ไว้ที่ไหน
superartsy

ด้านบนคุณสามารถดูได้ ... enum สาธารณะ EnumStates
Thulasiram

2

เหมือนกับของ Mike (ซึ่งฝังอยู่ระหว่างการตอบสนองที่ยืดยาว)

model.truckimagelocation เป็นคุณสมบัติอินสแตนซ์คลาสของประเภทการแจงนับ TruckImageLocation

@Html.DropDownListFor(model=>model.truckimagelocation,Enum.GetNames(typeof(TruckImageLocation)).ToArray().Select(f=> new SelectListItem() {Text = f, Value = f, Selected = false}))

2

นี่คือรหัสทั่วไปส่วนใหญ่ที่จะใช้กับ Enums ทั้งหมด

public static class UtilitiesClass
{

    public static SelectList GetEnumType(Type enumType)
    {
        var value = from e in Enum.GetNames(enumType)
                    select new
                    {
                        ID = Convert.ToInt32(Enum.Parse(enumType, e, true)),
                        Name = e
                    };
        return new SelectList(value, "ID", "Name");
    }
}

วิธีการดำเนินการ

ViewBag.Enum= UtilitiesClass.GetEnumType(typeof (YourEnumType));

View.cshtml

 @Html.DropDownList("Type", (IEnumerable<SelectListItem>)ViewBag.Enum, new { @class = "form-control"})

1

คุณสามารถใช้ enum ในแบบจำลองของคุณ

Enum ของคุณ

public enum States()
{
  AL,AK,AZ,...WY
}

สร้างแบบจำลอง

public class enumclass
{
public States statesprop {get; set;}
}

ในมุมมอง

@Html.Dropdownlistfor(a=>a.statesprop)

คำถามล่าสุดคำตอบ kar
Anup

1

คำตอบที่ง่ายที่สุดใน MVC5 คือ Define Enum:

public enum ReorderLevels {
          zero = 0,
            five = 5,
            ten = 10,
            fifteen = 15,
            twenty = 20,
            twenty_five = 25,
            thirty = 30
        }

ผูกในมุมมอง:

        <div class="form-group">
            <label>Reorder Level</label>
            @Html.EnumDropDownListFor(m => m.ReorderLevel, "Choose Me", new { @class = "form-control" })
        </div>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.