MVC3 Razor DropDownListFor Enums


84

Đang cố gắng cập nhật dự án của tôi lên MVC3, điều mà tôi không thể tìm thấy:

Tôi có một loại dữ liệu đơn giản của ENUMS:

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

Cái mà tôi muốn sử dụng làm DropDown / SelectList trong chế độ xem của tôi về một mô hình có chứa kiểu dữ liệu này:

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

Khá đơn giản: khi tôi sử dụng chế độ xem tự động tạo cho lớp từng phần này, nó sẽ bỏ qua loại này.

Tôi cần một danh sách lựa chọn đơn giản đặt giá trị của enum làm mục đã chọn khi tôi nhấn gửi và xử lý thông qua Phương pháp AJAX - JSON POST.

Và hơn lượt xem (???!):

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

Cảm ơn trước cho lời khuyên!


8
Đối với bất cứ ai đi qua chủ đề này và đang sử dụng MVC 5.1 hoặc cao hơn, phương pháp helper @ Html.EnumDropDownListFor () bây giờ được xây dựng trong MVC - xem asp.net/mvc/overview/releases/mvc51-release-notes
mecsco

Câu trả lời:


55

Tôi vừa làm một cái cho dự án của riêng mình. Đoạn mã dưới đây là một phần của lớp trợ giúp của tôi, tôi hy vọng rằng tôi có tất cả các phương thức cần thiết. Viết bình luận nếu nó không hoạt động, và tôi sẽ kiểm tra lại.

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

Sử dụng nó như:

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

Cập nhật

Tôi đã tạo Trợ giúp Html thay thế. Tất cả những gì bạn cần làm để sử dụng chúng là thay đổi trang web cơ sở của bạn trongviews\web.config .

Với chúng, bạn chỉ có thể làm:

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

Thông tin thêm tại đây: http://blog.gauffin.org/2011/10/first-draft-of-my-alternative-html-helpers/


1
Được rồi, nó hoạt động theo cách nào đó, tôi chỉ gặp một lỗi biên dịch: Dòng 41: return htmlHelper.DropDownList (inputName, ToSelectList (typeof (TProperty), value.ToString ())); 'System.Web.Mvc.HtmlHelper <TModel>' không chứa định nghĩa cho 'DropDownList' và không có phương thức mở rộng nào 'DropDownList' chấp nhận đối số đầu tiên của loại 'System.Web.Mvc.HtmlHelper <TModel>' ( bạn đang thiếu một chỉ thị sử dụng hoặc tham khảo một hội)?
jordan.baucke

1
@jordan Tôi cũng bị lỗi tương tự. Bạn đã quản lý để khắc phục sự cố?
SF Developer

9
@filu @jordan thêm using System.Web.Mvc.Html;khi bạn cần truy cập vàoSelectExtensionsClass
Simon Hartcher

3
@Para Tôi đang gặp vấn đề tương tự, giá trị đã chọn không xuất hiện được chọn trong Chế độ xem. (Tôi đã phải thay đổi ((int)item).ToString()cho Enum.GetName(enumType, item)để có được SelectListItemlưu một cách chính xác như được lựa chọn, nhưng nó vẫn không làm việc)
Fernando Neira

1
Chỉ cần thêm một câu trả lời bên dưới cho vấn đề lựa chọn - bắt nguồn từ sự hiểu lầm về các hành vi của quá tải DropDownList.
Jon Egerton

199

Tôi đã tìm thấy một giải pháp đơn giản hơn cho việc này tại đây: 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);
}   }   }

Một dòng trong dao cạo sẽ làm điều đó:

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

Bạn cũng có thể tìm thấy mã để thực hiện nó với một phương thức mở rộng trong bài viết được liên kết.


6
Tôi nghĩ rằng điều này nên được đánh dấu là giải pháp. Điều tốt nhất không được đánh dấu bởi sự phức tạp mà bởi sự đơn giản.
Lord of Scripts

3
Đối với những người xem phiên bản DropDowList (như tôi): @ Html.DropDownList ("listName", SelectList mới (Enum.GetValues ​​(typeof (MyNamespace.Enums.States))))
dstr

2
@JonEgerton Nếu bạn có ý nghĩa giống tôi thì tôi đồng ý. Nếu bạn muốn hiển thị enums + mô tả + hình ảnh, bạn đã bị mất với giải pháp của Mike McLaughlin.
Elisabeth

1
Vấn đề duy nhất mà tôi tìm thấy với các giải pháp này là nó không ánh xạ chính xác giá trị đã chọn khi tải nó. Bên cạnh đó, khá tốt.
triangulito

3
@triangulito đây không phải là vấn đề gì cả :)@Html.DropDownListFor(model => model.State, new SelectList(Enum.GetValues(typeof(MyNamespace.Enums.States)),model.State))
VladL


17

Nếu bạn muốn một thứ thực sự đơn giản thì có một cách khác, tùy thuộc vào cách bạn lưu trữ trạng thái trong cơ sở dữ liệu.

Nếu bạn có một thực thể như thế này:

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

Sau đó, việc tạo trình đơn thả xuống sẽ dễ dàng như sau:

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

LINQ không đẹp sao?


bạn định nghĩa các Bang ở đâu trong Mô hình hay Chế độ xem?
superartsy

trong mô hình, vì nó được sử dụng bởi các mô hình lớp
sjmeverett

1
@stewartml Khi ViewModel của tôi có thuộc tính enum + "SelectedCodeProperty" thì đây là một thuộc tính quá nhiều trong bài đăng của bạn. Tại sao không có enum ở cả hai dưới dạng giá trị đã chọn đăng lại máy chủ + dưới dạng giá trị mục.
Elisabeth

13

Tôi đã có thể làm điều này trong một lớp lót.

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

8

Dựa trên câu trả lời được chấp nhận bởi @jgauffin, tôi đã tạo phiên bản của riêng mình, phiên bản EnumDropDownListFornày giải quyết vấn đề chọn mặt hàng.

Vấn đề được trình bày chi tiết trong một câu trả lời SO khác ở đây:, và về cơ bản là do sự hiểu lầm về hành vi của các quá tải khác nhau của DropDownList.

Mã đầy đủ của tôi (bao gồm quá tải cho htmlAttributesvv là:

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

Tôi đã viết điều này trên blog của tôi ở đây .


1
Đây là giải pháp duy nhất tôi đã gặp để chọn trước một cách chính xác giá trị phù hợp cho bảng liệt kê của tôi. Cảm ơn!
Edwin Groenendaal

Tuyệt vời. Đây chắc chắn phải là câu trả lời được chấp nhận - nó hoạt động; câu trả lời được chấp nhận là không.
neminem

3

Điều này sẽ hữu ích cho việc chọn một giá trị int từ enum: Đây SpecTypelà một inttrường ... và enmSpecTypelà một enum.

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

3

Tôi đã thực hiện thay đổi sau đối với phương thức SelectList để làm cho nó hoạt động tốt hơn một chút đối với tôi. Có thể nó sẽ hữu ích cho những người khác.

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

bạn định nghĩa EnumState ở đâu?
superartsy

trong top u có thể nhìn thấy nó ... EnumStates enum công cộng
Thulasiram

2

Giống như của Mike (bị chôn vùi giữa những câu trả lời dài dòng)

model.truckimagelocation là thuộc tính cá thể lớp của kiểu liệt kê TruckImageLocation

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

2

Đây là mã chung nhất sẽ được sử dụng cho tất cả các Enum.

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

Phương pháp hành động

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

View.cshtml

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

1

bạn có thể sử dụng enum trong mô hình của mình

Enum của bạn

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

làm cho một mô hình

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

trong tầm nhìn

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

Câu hỏi mới nhất Trả lời kar.
Anup

1

Câu trả lời dễ nhất trong MVC5 là Xác định Enum:

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

Ràng buộc trong Xem:

        <div class="form-group">
            <label>Reorder Level</label>
            @Html.EnumDropDownListFor(m => m.ReorderLevel, "Choose Me", new { @class = "form-control" })
        </div>
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.