【问题标题】:solution to the asp.net mvc drop down list selected value overrider problemasp.net mvc下拉列表选择值覆盖问题的解决方法
【发布时间】:2011-01-31 19:53:26
【问题描述】:

我编写了一个辅助方法来在我的 asp.net MVC 应用程序中将我的模型中的枚举显示为我的视图中的下拉列表。

这是我的代码:

public static List<SelectListItem> CreateSelectItemList<TEnum>(object enumObj,
                                                            string defaultItemKey,
                                                            bool sortAlphabetically,
                                                            object firstValueOverride)
    where TEnum : struct
    {
        var values = (from v in (TEnum[])Enum.GetValues(typeof(TEnum))
                      select new
                      {
                          Id = Convert.ToInt32(v),
                          Name = ResourceHelpers.GetResourceValue(AppConstants.EnumResourceNamespace,
                                                                  typeof(TEnum).Name, v.ToString())
                      });


        return values.ToSelectList(e => e.Name,
                                               e => e.Id.ToString(),
                                               !string.IsNullOrEmpty(defaultItemKey) ? ResourceHelpers.GetResourceValue(AppConstants.EnumResourceNamespace, defaultItemKey) : string.Empty,
                                               enumObj,
                                               sortAlphabetically,
                                               firstValueOverride);

    }

这实际上生成了选择项列表:

public static List<SelectListItem> ToSelectList<T>(
    this IEnumerable<T> enumerable,
    Func<T, string> text,
    Func<T, string> value,
    string defaultOption,
    object selectedVal,
    bool sortAlphabetically,
    object FirstValueOverride)
{

    int iSelectedVal = -1;

    if(selectedVal!=null)
    {
        try
        {
            iSelectedVal = Convert.ToInt32(selectedVal);
        }
        catch
        {
        }
    }

    var items = enumerable.Select(f => new SelectListItem()
    {
        Text = text(f),
        Value = value(f),
        Selected = (iSelectedVal > -1)? (iSelectedVal.ToString().Equals(value(f))) : false
    });

    #region Sortare alfabetica
    if (sortAlphabetically)
        items = items.OrderBy(t => t.Text);
    #endregion Sortare alfabetica

    var itemsList = items.ToList();

    Func<SelectListItem, bool> funct = null;
    string sValue = string.Empty;
    SelectListItem firstItem = null;
    SelectListItem overridenItem = null;
    int overridenIndex = 0;

    if (FirstValueOverride != null)
    {
        sValue = FirstValueOverride.ToString();

        funct = (t => t.Value == sValue);
        overridenItem = itemsList.SingleOrDefault(funct);
        overridenIndex = itemsList.IndexOf(overridenItem);

        if (overridenItem != null)
        {
            firstItem = itemsList.ElementAt(0);
            itemsList[0] = overridenItem;
            itemsList[overridenIndex] = firstItem;
        }
    }

    if(!string.IsNullOrEmpty(defaultOption))
        itemsList.Insert(0, new SelectListItem()
        {
            Text = defaultOption,
            Value = "-1"
        });

    return itemsList;
}

这是我调用的方法:

        public static MvcHtmlString EnumDropDownList<TEnum>(this HtmlHelper htmlHelper, 
                                                        object enumObj,
                                                        string name,
                                                        string defaultItemKey,
                                                        bool sortAlphabetically,
                                                        object firstValueOverride,
                                                        object htmlAttributes)
    where TEnum : struct
    {
        return htmlHelper.DropDownList(name,
                                        CreateSelectItemList<TEnum>(enumObj,
                                                                defaultItemKey,
                                                                sortAlphabetically,
                                                                firstValueOverride), 
                                         htmlAttributes);
    }

现在我遇到了here
描述的问题 当我调用此辅助方法并且输入的名称与属性的名称相同时,不会选择所选值。
那里描述的替代解决方案对我不起作用。唯一可行的解​​决方案是更改名称,而不是使用 FormCollection 使用模型绑定。 我不喜欢这种解决方法,因为我不能再使用 ViewModel 模式进行验证,而且我必须为每个枚举编写一些额外的代码。
我尝试编写一个自定义模型绑定器来以某种方式弥补这一点,但是当我开始操作时,我可以覆盖的方法都没有被调用。

有什么方法可以在不使用 FormCollection 的情况下做到这一点? 当 ASP.NET MVC 尝试将值放入我的输入字段并使其选择正确的值时,我可以以某种方式拦截它吗?

提前谢谢你。

【问题讨论】:

    标签: asp.net-mvc enums drop-down-menu


    【解决方案1】:

    我现在有一个解决方案
    这是 EnumDropDownList 函数的代码,问题中列出了其他函数:

    public static MvcHtmlString EnumDropDownList(this HtmlHelper htmlHelper,
                                                       object enumObj,
                                                       string name,
                                                       string defaultItemKey,
                                                       bool sortAlphabetically,
                                                       object firstValueOverride,
                                                       object htmlAttributes)
    {
    
        StringBuilder sbRezultat = new StringBuilder();
    
        int selectedIndex = 0;
    
        var selectItemList = new List<SelectListItem>();
    
    
        if (enumObj != null)
        {
            selectItemList = CreateSelectItemList(enumObj, defaultItemKey, true, null);
    
            var selectedItem = selectItemList.SingleOrDefault(item => item.Selected);
            if (selectedItem != null)
            {
                selectedIndex = selectItemList.IndexOf(selectedItem);
    
            }
        }
    
        var dict = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
    
    
        TagBuilder tagBuilder = new TagBuilder("select");
    
        tagBuilder.MergeAttribute("name", name,true);
    
        bool bReadOnly = false;
    
        //special case for readonly
        if(dict.ContainsKey("readonly"))
        {
            //remove this tag it won't work the way mvc renders it anyway
            dict.Remove("readonly");
            bReadOnly = true;
        }
    
        //in case the style element is completed if the drop down is not readonly
        tagBuilder.MergeAttributes(dict, true);
    
        if (bReadOnly)
        {
            //add a small javascript to make it readonly and add the lightgrey style
            tagBuilder.MergeAttribute("onchange", "this.selectedIndex=" + selectedIndex + ";",true);
            tagBuilder.MergeAttribute("style", "background: lightgrey", true);
        }
    
        sbRezultat.Append(tagBuilder.ToString(TagRenderMode.StartTag));
    
    
        foreach (var option in selectItemList)
        {
            sbRezultat.Append(" <option value='");
            sbRezultat.Append(option.Value);
            sbRezultat.Append("' ");
            if (option.Selected)
                sbRezultat.Append("selected");
            sbRezultat.Append(" >");
            sbRezultat.Append(option.Text);
    
    
            sbRezultat.Append("</option>");
        }
        sbRezultat.Append("</select>");
        return new MvcHtmlString(sbRezultat.ToString());
    }
    

    我还写了一个 For (EnumDropDownFor) 类型的泛型函数:

    public static MvcHtmlString EnumDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
                                    string defaultItemKey,
                                    bool sortAlphabetically,
                                    object firstValueOverride,
                                    object htmlAttributes)
        where TProperty : struct
    {
        string inputName = GetInputName(expression);
    
        object selectedVal = null;
        try
        {
            selectedVal = htmlHelper.ViewData.Model == null
                ? default(TProperty)
                : expression.Compile()(htmlHelper.ViewData.Model);
        }
        catch//in caz ca e ceva null sau ceva de genu'
        {
        }
    
        return EnumDropDownList(htmlHelper,
                                selectedVal,
                                inputName,
                                defaultItemKey,
                                sortAlphabetically,
                                firstValueOverride,
                                htmlAttributes);
    }
    

    还有一些辅助方法:

    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)
    {
        MethodCallExpression methodCallExpression = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }
    

    【讨论】:

    • MvcHtmlString(String) 构造函数已过时。请改用 MvcHtmlString.Create(String)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多