使用辅助方法在MVC3 / Razor中对DropDownList进行排序的最佳方法

时间:2011-08-28 19:02:39

标签: asp.net-mvc-3 razor drop-down-menu

嗨,所以我对MVC3和Razor很陌生,过去几天我一直在努力解决这个问题。我的项目架构师给了我一个任务来创建一个帮助方法来对MVC视图中的下拉列表进行排序。我有一个View从Controller中检索各种数据,我正在返回一些我希望出现在下拉列表中的值。我被告知不要在Controller中对它进行排序,也要将我们想要排序的字段传递给helper方法。我可以像下面这样做,但建筑师希望保持视图不受尖锐代码的影响:

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

所以我创建了一些示例代码和一些扩展方法来尝试让它工作。我的想法是复制现有的Html.DropDownList方法并允许传递'object htmlAttributes',这样我就可以将样式设置为方法调用的一部分。

到目前为止,这是我的代码。我在Edit Controller方法中返回ViewBag.StudyTypes中下拉列表的数据:

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'参数,因为IEnumerable上的OrderBy需要一个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 个答案:

答案 0 :(得分:5)

代码的第一个和最重要的部分将是摆脱任何ViewBag/ViewData(我个人认为是MVC应用程序的癌症)并使用视图模型和强类型视图。

让我们首先定义一个视图模型,该模型将代表我们的视图将使用的数据(在此示例中为dropdownlist):

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
        );
    }
}

答案 1 :(得分:0)

如果您使用的是数据库,则可以使用查询来定义排序元素

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);
                    }
}

答案 2 :(得分:0)

只需在将项目返回到下拉列表之前添加排序。

这样做:

模型: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并直接使用函数来填充值。