MVC中的通用复选框列表视图模型

时间:2013-03-30 08:28:20

标签: asp.net-mvc asp.net-mvc-3 viewmodel checkboxlist

我想创建一个通用的复选框列表视图模型,所以我得到了这个:

public class ChckboxListViewModel<T>
{
    public List<CheckboxViewModel<T>> CheckboxList { get; set; }
    public IEnumerable<T> SelectedValues
    {
        get { return CheckboxList.Where(c => c.IsSelected).Select(c => c.Value); }
    }

    public ChckboxListViewModel()
    {
        CheckboxList = new List<CheckboxViewModel<T>>();
    }
}

public class CheckboxViewModel<T>
{
    public string Label { get; set; }
    public T Value { get; set; }
    public bool IsSelected { get; set; }

    public CheckboxViewModel(string i_Label, T i_Value, bool i_IsSelected)
    {
        Label = i_Label;
        Value = i_Value;
        IsSelected = i_IsSelected;
    }
}

它由不同的视图模型用于表示不同状态的过滤器:

public class FaultListFilters
{
    public string SearchKeyword { get; set; }
    public ChckboxListViewModel<Fault.eFaultStatus> StatusFilter { get; set; }

    public FaultListFilters()
    {
        SearchKeyword = null;
        StatusFilter = new ChckboxListViewModel<Fault.eFaultStatus>();

        StatusFilter.CheckboxList.Add(new CheckboxViewModel<Fault.eFaultStatus>(FaultManagementStrings.OpenStatus,Fault.eFaultStatus.Open,true));
        StatusFilter.CheckboxList.Add(new CheckboxViewModel<Fault.eFaultStatus>(FaultManagementStrings.InProgressStatus, Fault.eFaultStatus.InProgress, true));
        StatusFilter.CheckboxList.Add(new CheckboxViewModel<Fault.eFaultStatus>(FaultManagementStrings.ClosedStatus, Fault.eFaultStatus.Close, false));

    }
}

现在我找不到显示编辑器的正确方法或为这种视图模型创建编辑器模板,因为它是Generic。

我不希望为ChckboxListViewModel<int>创建单独的编辑器模板,然后为ChckboxListViewModel<Fault.eFaultStatus>创建另一个编辑模板,依此类推......

在这种情况下使用泛型是否是一个愚蠢的想法?

是否有其他方法可以在MVC中表示和显示复选框列表?

我已经完成了以下操作,但由于某种原因,模块没有绑定:

@using (Html.BeginForm("FaultManagement", "Faults", FormMethod.Get, null))
{

    for (int i=0 ; i<Model.FaultListFilters.StatusFilter.CheckboxList.Count() ; i++)
    {
        @Html.HiddenFor(m => m.FaultListFilters.StatusFilter.CheckboxList[i].Value)
        @Html.CheckBoxFor(m => m.FaultListFilters.StatusFilter.CheckboxList[i].IsSelected)
        @Html.LabelFor(m=> m.FaultListFilters.StatusFilter.CheckboxList[i].IsSelected,Model.FaultListFilters.StatusFilter.CheckboxList[i].Label)
    }

    <input type="submit" />
}

2 个答案:

答案 0 :(得分:2)

  

在这种情况下使用泛型是否是一个愚蠢的想法?

不要以为是。

  

是否有其他方法可以在MVC中表示和显示复选框列表?

我会编写一个自定义HTML帮助器:

public static class HtmlExtensions
{
    public static IHtmlString CheckboxListFor<TModel>(
        this HtmlHelper<TModel> html, 
        Expression<Func<TModel, IEnumerable<string>>> ex, 
        IEnumerable<string> possibleValues)
    {
        var metadata = ModelMetadata.FromLambdaExpression(ex, html.ViewData);
        var availableValues = (IEnumerable<string>)metadata.Model;
        var name = ExpressionHelper.GetExpressionText(ex);
        return html.CheckboxList(name, availableValues, possibleValues);
    }

    private static IHtmlString CheckboxList(this HtmlHelper html, string name, IEnumerable<string> selectedValues, IEnumerable<string> possibleValues)
    {
        var result = new StringBuilder();

        foreach (string current in possibleValues)
        {
            var label = new TagBuilder("label");
            var sb = new StringBuilder();

            var checkbox = new TagBuilder("input");
            checkbox.Attributes["type"] = "checkbox";
            checkbox.Attributes["name"] = name;
            checkbox.Attributes["value"] = current;
            var isChecked = selectedValues.Contains(current);
            if (isChecked)
            {
                checkbox.Attributes["checked"] = "checked";
            }

            sb.Append(checkbox.ToString());
            sb.Append(current);

            label.InnerHtml = sb.ToString();
            result.Append(label);
        }
        return new HtmlString(result.ToString());
    }
}

然后你可以有一个视图模型:

public class FaultListFiltersViewModel
{
    public IEnumerable<string> SelectedStatusFilters { get; set; }
    public IEnumerable<string> AvailableStatusFilters
    {
        get
        {
            return new[] { "Label 1", "Label 2", "Label 3" }
        }
    }
}

在视图中你可以使用帮助器:

@Html.CheckBoxListFor(x => x.SelectedStatusFilters, Model.AvailableStatusFilters)

答案 1 :(得分:0)

这是另一个实现,它将更好地支持bootstrap按钮组标签(因为它要求它们分开)和枚举类型选择值。

    public static IHtmlString CheckboxListFor<TModel, TKey>(this HtmlHelper<TModel> helper, Expression<Func<TModel, IEnumerable<TKey>>> ex, Dictionary<TKey, string> i_PossibleOptions, object i_LabelHtmlAttributes)
        where TKey : struct, IConvertible
    {
        var metadata = ModelMetadata.FromLambdaExpression(ex, helper.ViewData);
        var selectedValues = (IEnumerable<TKey>)metadata.Model;
        var name = ExpressionHelper.GetExpressionText(ex);
        return helper.CheckboxList(name, selectedValues, i_PossibleOptions, i_LabelHtmlAttributes);
    }

    private static IHtmlString CheckboxList<TKey>(this HtmlHelper helper, string name, IEnumerable<TKey> i_SelectedValues, Dictionary<TKey, string> i_PossibleOptions, object i_LabelHtmlAttributes)
        where TKey : struct, IConvertible
    {
        if (!typeof(TKey).IsEnum) throw new ArgumentException("T must be an enumerated type");

        var result = new StringBuilder();

        foreach (var option in i_PossibleOptions)
        {
            var label = new TagBuilder("label");
            label.MergeAttributes(new RouteValueDictionary(i_LabelHtmlAttributes));
            label.Attributes["for"] = string.Format("{0}",option.Key.ToString());
            label.InnerHtml = option.Value;

            var checkbox = new TagBuilder("input");
            checkbox.Attributes["type"] = "checkbox";
            checkbox.Attributes["name"] = name;
            checkbox.Attributes["id"] = string.Format("{0}", option.Key.ToString());
            checkbox.Attributes["value"] = option.Key.ToString();

            bool isChecked = ((i_SelectedValues != null) && (i_SelectedValues.Contains(option.Key)));
            if ( isChecked )
            {
                checkbox.Attributes["checked"] = "checked";
            }

            result.Append(checkbox);
            result.Append(label);
        }
        return new HtmlString(result.ToString());
    }

然后视图模型看起来像这样:

public class FaultListFilters
{
    [Display(ResourceType = typeof(FaultManagementStrings), Name = "SearchKeyword")]
    public string SearchKeyword { get; set; }
    public Dictionary<Fault.eFaultStatus, string> PossibleFaultStatuses 
    {
        get 
        {
            var possibleFaultStatuses = new Dictionary<Fault.eFaultStatus, string>();
            possibleFaultStatuses.Add(Fault.eFaultStatus.Open, FaultManagementStrings.OpenStatus);
            possibleFaultStatuses.Add(Fault.eFaultStatus.InProgress, FaultManagementStrings.InProgressStatus);
            possibleFaultStatuses.Add(Fault.eFaultStatus.Close, FaultManagementStrings.ClosedStatus);
            return possibleFaultStatuses;
        }
    }
    public IEnumerable<Fault.eFaultStatus> SelectedFaultStatuses { get; set; }

    public FaultListFilters()
    {
        SearchKeyword = null;
        SelectedFaultStatuses = new[] { Fault.eFaultStatus.Open, Fault.eFaultStatus.InProgress };
    }
}

并且用法保持不变(除了我添加了标签html属性)

    <div class="btn-group">
    @Html.CheckboxListFor(m => m.FaultListFilters.SelectedFaultStatuses, Model.FaultListFilters.PossibleFaultStatuses, new { Class="btn"})
</div>