【问题标题】:How to use a radio button to select a list item in MVC3如何使用单选按钮选择 MVC3 中的列表项
【发布时间】:2011-07-13 09:53:03
【问题描述】:

我需要向我的用户提供一个包选项列表,他们从中选择一个。我不想使用单选按钮列表,因为每个列表项都需要相当复杂的模板。原谅我,但我似乎无法弄清楚如何将一列单选按钮链接到我的视图模型中的选择属性。

我的视图模型有一个SelectedPackageId (int) 和一个代表各个包的MemberPackageListItem 视图模型列表。 MemberPackageListItem 有一个PackageId (int),所以我需要将所选项目的PackageId 耦合到根视图模型的SelectedPackageId

我很难发布代码,因为继承等掩盖了您希望看到的大部分内容,所以我希望我的概述是一个相当常见的场景,以及在这种场景中使用单选按钮的一些一般准则足以帮助我继续。

【问题讨论】:

    标签: asp.net asp.net-mvc asp.net-mvc-3 razor


    【解决方案1】:

    我建议使用 HtmlHelper 来呈现您的单选按钮列表,如下所示:

        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString RadioButtonListFor<TModel, TList, TSelectedItem>(
            this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TList>> expression,
            Expression<Func<TModel, TSelectedItem>> selectedItem)
        {
            return RadioButtonListFor(htmlHelper, expression, selectedItem, null /* htmlAttributes */);
        }
    
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString RadioButtonListFor<TModel, TList, TSelectedItem>(
            this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TList>> expression, 
            Expression<Func<TModel, TSelectedItem>> selectedItem, object htmlAttributes)
        {
            return RadioButtonListFor(htmlHelper, expression, selectedItem, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }
    
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
        public static MvcHtmlString RadioButtonListFor<TModel, TList, TSelectedItem>(
            this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TList>> expression, 
            Expression<Func<TModel, TSelectedItem>> selectedItem, IDictionary<string, object> htmlAttributes)
        {
            if (expression == null)
            {
                throw new ArgumentNullException("expression");
            }
    
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            IEnumerable<SelectListItem> items = null;
            if (metadata.Model != null)
            {
                IEnumerable<SelectListItem> modelItems = (IEnumerable<SelectListItem>)metadata.Model;
                if (modelItems != null)
                {
                    items = modelItems;
                }
            }
    
            ModelMetadata selectedItemMetadata = ModelMetadata.FromLambdaExpression(selectedItem, htmlHelper.ViewData);
    
            return RadioButtonListHelper(htmlHelper, metadata, selectedItemMetadata, ExpressionHelper.GetExpressionText(selectedItem), items, htmlAttributes);
        }
    
        private static MvcHtmlString RadioButtonListHelper(HtmlHelper htmlHelper, ModelMetadata metadata, 
            ModelMetadata selectedItemMetadata, string name, IEnumerable<SelectListItem> selectList, IDictionary<string, object> htmlAttributes)
        {
            // Verify arguments
            if (String.IsNullOrEmpty(name)) throw new ArgumentNullException("name", "Name cannot be null");
            if (selectList == null) throw new ArgumentNullException("selectList", "Select list cannot be null");
            if (selectList.Count() < 1) throw new ArgumentException("Select list must contain at least one value", "selectList");
    
            string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
            string fullId = htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix + "_" + name;
    
            IDictionary<string, object> validationAttributes = htmlHelper
                .GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(name), selectedItemMetadata);
    
            // Define items
            StringBuilder items = new StringBuilder();
    
            // Loop through items
            Int32 index = 0;
            foreach (SelectListItem i in selectList)
            {
    
                // Define check box input
                TagBuilder input = new TagBuilder("input");
                input.MergeAttribute("type", "radio");
                input.MergeAttribute("name", fullName, true);
                if (i.Selected)
                    input.MergeAttribute("checked", "checked");
                input.MergeAttribute("value", i.Value);
                if (index == 0)
                    input.MergeAttributes(validationAttributes);
                input.MergeAttributes(htmlAttributes);
    
                // Define label
                TagBuilder label = new TagBuilder("label");
                label.MergeAttribute("for", fullId + "[" + index.ToString() + "].Selected");
                label.InnerHtml = i.Text;
    
                // Add item
                items.AppendFormat("\r\t<div>\r\t\t{0}\r\t\t{1}\r\t</div>",
                    input.ToString(TagRenderMode.Normal),
                    label.ToString(TagRenderMode.Normal));
    
                index++;
            }
            // Return list
            return new MvcHtmlString(items.ToString() + "\r");
        }
    

    请注意MemberPackageListItem 必须是IEnumerable&lt;SelectListItem&gt; 类型。用法如下(Razor语法):

        @Html.RadioButtonListFor(m => m.MemberPackageListItem, m => m.SelectedPackageId)
    

    辅导员

    【讨论】:

      【解决方案2】:

      虽然我很欣赏@counsellorben 回答的技术全面性,并将保留它以备将来使用,但今天我找到了一个更直接且并非完全笨拙的 jQuery 解决方案。选择器可能更具体,但我现在不需要。我的解决方案如下。单选类型输入按其名称属性分组,每行都有不同的索引。因此:

      $(function () {
          // Back up current names of package radio buttons, then make all their names the same for grouping.
          $("#packageForm :radio[name$='.IsSelected']").each(function () {
              $(this).attr("oldname", $(this).attr("name"));
          });
          $(":radio[name$='.IsSelected']").attr("name", "Package.IsSelected");
      
          // Hook the 'submit' click to restore original radio button names.
          $("#packageForm :submit").click(function () {
              $(":radio[name='Package.IsSelected']").each(function () {
                  $(this).attr("oldname", $(this).attr("name"));
              });
          });
      });  
      

      IsSelected 是我每行的属性,它告诉我该行是否被选中,它不是 jQuery 或 DOM 属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多