创建一个自定义html扩展,它将像ListBoxFor一样工作但输出复选框呢?

时间:2012-01-03 14:58:12

标签: asp.net-mvc

我正在尝试创建(或者更好地找到)一个自定义html扩展方法,该方法与ListBoxFor类似的工作方式有效,但是呈现一组复选框而不是选择多个。

解决这个问题的最佳方式是什么?我很好奇ListBoxFor方法是如何工作的,当它只传递一个表达式和一个可枚举的SelectListItems时,它只选择了默认项。它没有通过模型,所以它如何知道何时选择正确的项目(不知何故它似乎能够做到这一点)?另外,它如何根据匿名对象编写html属性?

1 个答案:

答案 0 :(得分:2)

您尚未提供任何有关您要实现的目标的详细信息和具体示例。到目前为止,您还没有提供任何源代码,以解决您遇到的问题。下次在StackOverflow上提出问题时,请这样做,以使您的问题更有意义,并专注于特定问题。

无论如何,这是一个例子。假设您已定义了一个视图模型:

public class MyViewModel
{
    public IEnumerable<string> SelectedValues { get; set; }
    public IEnumerable<SelectListItem> Values { get; set; }
}

和一个控制器,它将使用值填充此视图模型,并希望在POST操作中获取视图中的选定值:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            SelectedValues = new[] { "1", "3" },
            Values = new[]
            {
                new SelectListItem { Value = "1", Text = "item 1" },
                new SelectListItem { Value = "2", Text = "item 2" },
                new SelectListItem { Value = "3", Text = "item 3" },
            }
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        // model.SelectedValues will contain the ids of items that were checked
        // in the checkbox list
    }
}

然后是一个视图:

@model MyViewModel

@using (Html.BeginForm())
{
    @Html.CheckBoxListFor(x => x.SelectedValues, Model.Values, null)
    <button type="submit">OK</button>
}
好的,到目前为止一切顺利。最后一部分是尝试实现这个CheckBoxListFor帮助器。显然,根据您的具体要求和背景,可能有很多可能的方法(请参阅答案开头的评论)。所以这里只是一些可以帮助您入门的示例实现:

public static class HtmlExtnsions
{
    public static IHtmlString CheckBoxListFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper, 
        Expression<Func<TModel, TProperty>> expression, 
        IEnumerable<SelectListItem> selectList,
        object htmlAttributes
    )
    {
        var name = ExpressionHelper.GetExpressionText(expression);
        string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
        var values = GetModelStateValue(htmlHelper.ViewData, fullHtmlFieldName, typeof(string[]));
        if (values == null)
        {
            values = htmlHelper.ViewData.Eval(fullHtmlFieldName);
        }

        if (values != null)
        {
            var collection =
                from object value in values as IEnumerable
                select Convert.ToString(value, CultureInfo.CurrentCulture);
            var hashSet = new HashSet<string>(collection, StringComparer.OrdinalIgnoreCase);
            var list = new List<SelectListItem>();
            foreach (var item in selectList)
            {
                item.Selected = ((item.Value != null) ? hashSet.Contains(item.Value) : hashSet.Contains(item.Text));
                list.Add(item);
            }
            selectList = list;
        }

        var sb = new StringBuilder();
        foreach (var item in selectList)
        {
            var checkbox = new TagBuilder("input");
            checkbox.Attributes["type"] = "checkbox";
            checkbox.Attributes["name"] = fullHtmlFieldName;
            checkbox.Attributes["value"] = item.Value;
            checkbox.GenerateId(fullHtmlFieldName);
            if (item.Selected)
            {
                checkbox.Attributes["checked"] = "checked";
            }
            sb.Append(checkbox.ToString(TagRenderMode.SelfClosing));
            sb.Append(item.Value);
        }

        return new HtmlString(sb.ToString());
    }

    private static object GetModelStateValue(ViewDataDictionary viewData, string key, Type destinationType)
    {
        ModelState modelState;
        if (viewData.ModelState.TryGetValue(key, out modelState) && modelState.Value != null)
        {
            return modelState.Value.ConvertTo(destinationType, null);
        }
        return null;
    }
}