CheckBoxList и RadioButtonList в ASP.NET MVC

25 Дек
2011

Я совсем недавно начал работать с ASP.NET MVC и сразу удивился отсутствием элементов управления CheckBoxList и RadioButtonList в ASP.NET MVC 3. В этой статье я покажу решение данной проблемы с помощью создания своих контролов.

Топик написан как альтернативный взгляд на создание элементов управления из этой статьи.



Введение


При написания элементов управления я ориентировался на исходные коды уже существующих DropDownList и ListBox чтобы сохранить стиль кода и аналогичность перегрузок. Это оградит пользователей от формирования данных каким-то новым способом, а также предоставит возможность прозрачно менять элементы управления CheckBoxList и RadioButtonList на DropDownList и ListBox, если возникнет такая необходимость.

Реализация


Элементы управления находятся в статическом классе, который состоит из множества перегрузок, а также внутренних и приватных вспомогательных методов. Я не буду описывать все вспомогательные методы, а разберу только главный из них, который использует все остальные.

Все перегрузки приводят в метод InputInternal, в котором происходит получение списка из ViewData (если мы его явно не передали через одну из перегрузок), после чего идет попытка получения заранее выбранных значений в списке.

var usedViewData = false;

if (inputList == null)
{
    inputList = htmlHelper.GetInputData(fullName);
    usedViewData = true;
}

var defaultValue = GetDefaultValue(htmlHelper, fullName, allowMultiple, usedViewData);

if (defaultValue != null)
{
    inputList = GetListWithDefaultValue(inputList, defaultValue, allowMultiple);
}


После подготовки списка происходит генерация html-кода, который отображает список. Если есть какие-то ошибки в modelState, то к списку добавляется css класс для отображения ошибки во view через JavaScript.

var listItemBuilder = new StringBuilder();

if (inputList != null)
{
    foreach (var item in inputList)
        listItemBuilder.AppendLine(InputItemToHtml(item, allowMultiple, fullName));
}

var tagBuilder = new TagBuilder("ul")
{
    InnerHtml = listItemBuilder.ToString()
};

tagBuilder.Attributes.Add("style", "padding:0");
tagBuilder.MergeAttributes(htmlAttributes, true /* replaceExisting */);
tagBuilder.GenerateId(fullName);

ModelState modelState;

if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState))
{
    if (modelState.Errors.Count > 0)
        tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}

tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name));

return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);


В конечном итоге у нас получается html-код такого вида (пример для списка с радиокнопками).

<ul id="RadioButtonTestItems" style="padding:0">
    <li style="list-style-type:none;">
        <label>
            <input name="RadioButtonItems" type="radio" value="Value1"></input>
            <span>Item1</span>
        </label>
    </li>
    <li style="list-style-type:none;">
        <label>
            <input name="RadioButtonItems" type="radio" value="Value2"></input>
            <span>Item2</span>
        </label>
    </li>
</ul>


Примеры использования


В качестве примера была создана модель Home с двумя свойствами: коллекция строк CheckBoxTestItems, в которой может быть несколько значений отмеченных чекбоксами (либо null если не выбран ни один из чекбоксов) и строка RadioButtonTestItems для хранения значения, которое было выбрано с помощью радиокнопок (также может оказаться null).

public class Home
{
    public ICollection<string> CheckBoxTestItems { get; set; }
    public string RadioButtonTestItems { get; set; }
}


Также в качестве примера было изменено содержание стандартного View для заглавной страницы. В нем создается форма с двумя списками типов CheckBoxList и RadioButtonList.

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)

    @Html.CheckBoxList("CheckBoxTestItems")
    @Html.RadioButtonList("RadioButtonTestItems")

    <p>
        <input type="submit" value="Submit" />
    </p>
}


В контроллере создан метод для генерации списков и добавления их в ViewBag. В этом контроллере я использую разные способы генерации списков, чтобы показать как можно больше возможностей элементов управления. В списке с чекбоксами в качестве данных выступает массив строк, а с помощью другого массива проставляются заранее отмеченные чекбоксы. В списке с радиокнопками я показал, как можно использовать значения, которые не являются копией текста рядом с контролом. Такая функциональность требуется, когда в качестве значений выступает ID какой-либо записи в базе данных.

private void GenerateListItems()
{
    var checkBoxTestItems = new[] { "CheckBoxTestItem1", "CheckBoxTestItem2", "CheckBoxTestItem3", "CheckBoxTestItem4" };
    var checkBoxTestItemsChecked = new[] { "CheckBoxTestItem2", "CheckBoxTestItem4" };

    ViewBag.CheckBoxTestItems = new MultiSelectList(checkBoxTestItems, checkBoxTestItemsChecked);


    var radioButtonTestItems = new List<SelectListItem>();

    for (var radioButtonTestItemNumber = 1; radioButtonTestItemNumber <= 4; radioButtonTestItemNumber++)
    {
        var selectListItem = new SelectListItem
        {
            Text = "RadioButtonTestItem" + radioButtonTestItemNumber,
            Value = "RadioButtonTestItemValue" + radioButtonTestItemNumber
        };

        radioButtonTestItems.Add(selectListItem);
    }

    ViewBag.RadioButtonTestItems = radioButtonTestItems;
}


И наконец действие Index. В нем вызывается описанный выше метод генерации списков, а также вывод из модели выбранных в списках значений после отправки формы.

public ActionResult Index()
{
GenerateListItems();
return View();
}

[HttpPost]
public ActionResult Index(Home model)
{
if (model.CheckBoxTestItems != null)
{
foreach (var checkBoxTestItem in model.CheckBoxTestItems)
ModelState.AddModelError(«», string.Format(«Checked CheckBox item: {0}», checkBoxTestItem));
}

if (model.RadioButtonTestItems != null)
{
ModelState.AddModelError(«», string.Format(«Checked SelectButton item: {0}», model.RadioButtonTestItems));
}

GenerateListItems();
return View(model);
}

Заключение


В конечном итоге получаем такой пример использования списков.



В заключение хочу сказать, что весь код написан несколько дней назад, так что возможны баги. Исходные коды доступны на GitHub.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх