Лучший способ отсортировать DropDownList в MVC3 / Razor, используя вспомогательный метод - PullRequest
5 голосов
/ 28 августа 2011

Привет, так что я довольно новичок в MVC3 и Razor, и я пытался разобраться с этим в последние несколько дней. Мой архитектор проекта дал мне задание создать вспомогательный метод, который сортирует выпадающий список в MVC View. У меня есть представление, которое получает различные данные из контроллера, и я возвращаю некоторые значения, которые я хочу отобразить в раскрывающемся списке. Мне сказали не сортировать его в контроллере, а также передавать поле, по которому мы хотим отсортировать, в вспомогательный метод. Я мог бы сделать это, как показано ниже, но архитектор хочет, чтобы представление было свободно от острого кода:

@Html.DropDownListFor(model => model.StudyName, new SelectList(ViewBag.StudyTypes, "Value", "Text").OrderBy(l => l.Text))

Итак, я создал пример кода и несколько методов расширения, чтобы попытаться заставить его работать. Моя идея состоит в том, чтобы скопировать существующий метод Html.DropDownList и разрешить передачу «object htmlAttributes», чтобы я мог установить стиль как часть вызова метода.

Вот мой код. Я возвращаю данные для раскрывающегося списка в ViewBag.StudyTypes в методе Edit Controller:

public ActionResult Edit(int id)
{
    IEnumerable<SelectListItem> mySelectList = new List<SelectListItem>();
    IList<SelectListItem> myList = new List<SelectListItem>();

    for (int i = 0; i < 5; i++)
    {
        myList.Add(new SelectListItem() 
            { Value = i.ToString(), Text = "My Item " + i.ToString(), Selected = i == 2 }
        );
    }

    mySelectList = myList;
    ViewBag.StudyTypes = mySelectList;

    StudyDefinition studydefinition = db.StudyDefinitions.Find(id);

    return View(studydefinition);
}

Вот мой код просмотра:

    @model MyStudyWeb.Models.StudyDefinition

@using MyStudyWeb.Helpers

@{
    ViewBag.Mode = "Edit";
}
<div>
    @Html.DropDownListSorted(new SelectList(ViewBag.StudyTypes, "Value", "Text"))<br />
    @Html.DropDownListSorted("MyList", new SelectList(ViewBag.StudyTypes, "Value", "Text"))<br />
</div>

Наконец, ниже приведены методы расширения, которые я пытаюсь заставить работать. Первый метод расширения ничего не делает, я просто получаю пробел в этой точке в представлении. Второй метод вроде работает, но он уродлив. Для третьего метода я не знаю, как указать параметр 'order by', так как OrderBy в IEnumerable ожидает выражение Linq.

namespace StudyDefinition.Helpers
{
    public static class HtmlHelperExtensions
    {
        // 1st sort method: sort the passed in list and return a new sorted list
        public static SelectList DropDownListSorted(this HtmlHelper helper, IEnumerable<SelectListItem> selectList)
        {
            var x = new SelectList(selectList.ToList()).OrderBy(l => l.Text);

            return x as SelectList;
        }

        // 2nd sort method: return IHtml string and create <select> list manually
        public static IHtmlString DropDownListSorted(this HtmlHelper helper, string name, SelectList selectList)
        {
            StringBuilder output = new StringBuilder();
            (selectList).OrderBy(l => l.Text);

            output.Append("<select id=" + name + " name=" + name + ">");

            foreach (var item in selectList)
            {
                output.Append("<option value=" + item.Value.ToString() + ">" + item.Text + "</option>");
            }

            output.Append("</select>");

            return MvcHtmlString.Create(output.ToString());
        }

        // 3rd sort method: pass in order by parameter - how do I use this?
        public static IHtmlString DropDownListSorted(this HtmlHelper helper, string name, SelectList selectList, string orderBy)
        {
            StringBuilder output = new StringBuilder();

            //How do I use the orderBy parameter?
            (selectList).OrderBy(l => l.Text);

            output.Append("<select id=" + name + " name=" + name + ">");

            foreach (var item in selectList)
            {
                output.Append("<option value=" + item.Value.ToString() + ">" + item.Text + "</option>");
            }

            output.Append("</select>");

            return MvcHtmlString.Create(output.ToString());
        }        
    }
}

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

  • Должен ли я вернуть SelectList или MvcHtmlString, или что-то еще полностью?

  • Для первого метода расширения, как получить возвращенный список SelectList для отображения в представлении?

  • Как передать параметр в мои методы расширения, который определяет порядок сортировки?

  • Как передать параметр 'object htmlAttributes' и как применить этот объект / параметр к списку SelectList?

Если у кого-то есть идеи или предложения, я буду признателен за отзывы:)

Ответы [ 3 ]

5 голосов
/ 28 августа 2011

Первая и самая важная часть вашего кода будет избавляться от любого ViewBag/ViewData (который я лично считаю раком для приложений MVC) и использовать модели представлений и строго типизированные представления.

Итак, давайте начнем с определения модели представления, которая будет представлять данные, с которыми будет работать наше представление (dropdownlistg в этом примере):

public class MyViewModel
{
    public string SelectedItem { get; set; }
    public IEnumerable<SelectListItem> Items { get; set; }
}

тогда у нас может быть контроллер:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            // I am explicitly putting some items out of order
            Items = new[]
            {
                new SelectListItem { Value = "5", Text = "Item 5" },
                new SelectListItem { Value = "1", Text = "Item 1" },
                new SelectListItem { Value = "3", Text = "Item 3" },
                new SelectListItem { Value = "4", Text = "Item 4" },
            }
        };
        return View(model);
    }
}

и представление:

@model MyViewModel
@Html.DropDownListForSorted(
    x => x.SelectedItem, 
    Model.Items, 
    new { @class = "foo" }
)

и, наконец, последний фрагмент - это вспомогательный метод, который сортирует выпадающий список по значению (вы можете адаптировать его для сортировки по тексту):

public static class HtmlExtensions
{
    public static IHtmlString DropDownListForSorted<TModel, TProperty>(
        this HtmlHelper<TModel> helper, 
        Expression<Func<TModel, TProperty>> expression, 
        IEnumerable<SelectListItem> items, 
        object htmlAttributes
    )
    {
        var model = helper.ViewData.Model;
        var orderedItems = items.OrderBy(x => x.Value);
        return helper.DropDownListFor(
            expression, 
            new SelectList(orderedItems, "Value", "Text"), 
            htmlAttributes
        );
    }
}
0 голосов
/ 06 февраля 2015

Просто добавьте сортировку перед возвратом элементов в выпадающий список.

Сделайте это:

Модели: StudyViewModel.cs

public class StudyViewModel {
    public string StudyName { get; set; }
    public string StudyTypes { get; set; }
}

Контроллер: StudyController.cs

using System.Web.Mvc;
public class StudyController 
{
    public List<SelectListItem> studyTypes() 
    {
        List<SelectListItem> itemList = new List<SelectListItem>();
        for (var i=0; i<5; i++)
        {
            itemList.Add = new SelectListItem({
                Value = i.ToString();
                Text = "My Item";
            });
        }
        // You can sort here....
        List<SelectListItem> sortedList = itemList.OrderBy(x=>x.Text);
        return sortedList;
    }

    public ActionResult Edit(int id)
    {
        //You won't need this because you get it using your
        //controller's routine, instead 
        //ViewBag.StudyTypes = studySlots.OrderBy(e => e.Value);

        //-- unless you need to add these values to the model for 
        // some reason (outside of filling the ddl), in which case....
        // StudyViewModel svm = new StudyViewModel();
        // svm.StudyTypes = studySlots.OrderBy(e => e.Value);
        // svm.StudyName = "My Item";
        // return View(svm);

        // Otherwise, just....
        return View();
    }
}

Просмотр: Edit.cshtml

@Html.DropDownListFor(model => model.StudyName)
    .OptionLabel('Select...')
    .DataTextField('Text')
    .DataValueField('Value')
    .Datasource(source => 
    {
       // This is where you populate your data from the controller
        source.Read(read => 
        {
            read.Action("studyTypes", "Study");
        });
    })
    .Value(Model.StudyName != null ? Model.StudyName.ToString() : "")
)

Этот способ позволит избежать ViewBags и просто использовать функцию для непосредственного заполнения значений.

0 голосов
/ 17 марта 2014

Если вы используете базу данных, вы можете использовать запрос для определения элемента сортировки

using (BDMMContext dataContext = new BDMMContext())
{
foreach (Arquiteto arq in dataContext.Arquitetos.SqlQuery("SELECT * FROM  Arquitetos ORDER BY Nome"))
                    {
                        SelectListItem selectItem = new SelectListItem { Text = arq.Nome, Value = arq.Arquiteto_Id.ToString() };
                        //
                        list.Add(selectItem);
                    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...