2011-08-28 50 views
5

嗨,所以我對MVC3和Razor相當陌生,在過去的幾天裏我一直試圖讓自己的頭靠近它。我的項目架構師已經給我一個任務來創建一個幫助器方法,該方法對MVC視圖中的下拉列表進行排序。我有一個View從Controller中檢索各種數據,並返回一些我想要顯示在下拉列表中的值。我被告知不要在Controller中對它進行排序,並且還要將我們想要排序的字段傳遞給輔助方法。我能做到這一點像之下,但建築師希望保持觀點自由的升C代碼:使用幫助器方法在MVC3/Razor中對DropDownList進行排序的最佳方法

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

所以我創造了一些示例代碼和一些擴展方法,試圖得到它的工作。我的想法是複製現有的Html.DropDownList方法並允許傳遞'object htmlAttributes',這樣我可以將該樣式設置爲方法調用的一部分。

這是我的代碼到目前爲止。我倒返回數據爲下降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以在View中呈現?

  • 如何將參數傳遞給指定排序順序的擴展方法?

  • 如何傳遞'object htmlAttributes'參數,以及如何將此對象/參數應用於SelectList?

如果有人有一些想法或建議,那麼我會很感激一些反饋:)

回答

5

第一和代碼的最重要的部分將擺脫任何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" } 
) 

,最後的最後一塊是幫助遇見HOD將排序值下拉(你能適應它通過文本排序):

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

嗨@Darin非常感謝。但是,我正在處理現有系統,並且所有視圖都有多個下拉列表,並且它們全都作爲ViewBag屬性從控制器返回。所以我不能改變這種做法。其次,View已經在做'返回View(studydefinition)'這是Entity類。有沒有另一種方法可以返回視圖模型?第三,當我添加你的擴展方法時,DropDownListFor方法不被識別,我得到:'System.Web.Mvc.HtmlHelper'不包含'DropDownListFor'的定義 –

+3

@Ciaran Bruen,對於現有系統和ViewBag 。我只是提到它爲未來的代碼,以避免這種不好的做法。如果您有多個下拉列表,則只需在視圖模型上擁有多個「IEnumerable 」屬性。關於'return View(studydefinition)',這是將視圖模型傳遞給視圖的正確方法。第三,在'System.Web.Mvc.Html'命名空間中定義了'DropDownListFor'擴展方法,因此只需在包含'DropDownListForSorted'幫助器的文件頂部的這個命名空間中添加一個using以使其進入作用域。 –

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); 
        } 
} 
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,並直接使用函數來填充值。

相關問題