2011-08-28 14 views
5

Cześć, więc jestem całkiem nowy dla MVC3 i Brzytwy i próbuję się z tym pogodzić w ciągu ostatnich kilku dni. Otrzymałem zadanie od mojego architekta projektu, aby utworzyć metodę pomocniczą, która sortuje rozwijaną listę w widoku MVC. Mam widok, który pobiera różne dane z kontrolera i zwracam niektóre wartości, które chcę wyświetlić na liście rozwijanej. Powiedziano mi, żeby nie sortować go w kontrolerze, a także przekazywać pole, które chcemy sortować, do metody pomocniczej. Mogłem to zrobić jak poniżej, ale architekt chce utrzymać widok wolne od cis kodu:Najlepszy sposób sortowania DropDownList w MVC3/Razor za pomocą metody pomocnika

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

Więc stworzyliśmy przykładowy kod i niektóre metody rozszerzenie aby spróbować i dostać go do pracy. Moim pomysłem jest replikacja istniejącej metody Html.DropDownList i zezwolenie na przekazywanie 'object htmlAttributes', dzięki czemu mogę ustawić styl jako część wywołania metody.

Oto mój kod do tej pory. Wracam dane o spadku w ViewBag.StudyTypes w metodzie 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); 
} 

Oto moim zdaniem kod:

@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> 

Wreszcie poniżej są metody przedłużania Próbuję zabrać się do pracy. Pierwsza metoda rozszerzenia nic nie robi, po prostu dostaję pustą przestrzeń w tym miejscu w widoku. Drugi rodzaj prac, ale jest brzydki. W przypadku trzeciej metody nie wiem, jak określić parametr "order by", ponieważ OrderBy na IEnumerable oczekuje wyrażenia 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()); 
     }   
    } 
} 

ja naprawdę nie wiem, najlepsze podejście do podjęcia, nie może być znacznie prostszy sposób, że jestem całkowicie brakujący i mogę być w miejscu, gdzie nie widzę drewno na drzewach już. Kilka pytań:

  • Czy powinienem zwrócić SelectList lub MvcHtmlString, lub coś zupełnie innego?

  • Dla pierwszej metody rozszerzenia, w jaki sposób uzyskać zwróconą listę SelectList do renderowania w widoku?

  • Jak przekazać parametr do moich metod rozszerzenia, który określa kolejność sortowania?

  • Jak przekazać parametr object htmlAttributes i jak zastosować ten obiekt/parametr do SelectList?

Jeśli ktoś ma jakieś pomysły lub propozycje to bym wdzięczny za komentarze :)

Odpowiedz

5

Pierwszym i najważniejszymczęść kodu byłoby pozbyć się ViewBag/ViewData (co ja osobiście rozważyć jako rak dla aplikacji MVC) i używać modeli widoku i mocno wpisanych widoków.

Więc zacznijmy od zdefiniowania widoku modelu, które reprezentują dane naszym zdaniem będzie pracować z (a dropdownlistg w tym przykładzie):

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

wtedy możemy mieć Kontroler:

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

i widok:

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

i wreszcie ostatni kawałek jest pomocnikiem spełnione hod które będą sortować listę rozwijaną przez wartość (można ją dostosować do sortowania według tekstu):

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

Witam @ Darin, dzięki. Kilka problemów jednak pracuję nad istniejącym systemem, a wszystkie widoki mają wiele list rozwijanych i wszystkie są zwracane ze swoich kontrolerów jako właściwości ViewBag. Tak naprawdę nie mogę zmienić tego podejścia. Po drugie, widok robi już "widok powrotu (studydefinition)", który jest klasą Entity. Czy istnieje inny sposób, w jaki mogę zwrócić model widoku? Po trzecie, gdy dodaję twoją metodę rozszerzenia, metoda DropDownListFor nie jest rozpoznawana, otrzymuję: "System.Web.Mvc.HtmlHelper" nie zawiera definicji "DropDownListFor" –

+3

@Ciaran Bruen, OK dla istniejącego systemu i ViewBag . Właśnie wspomniałem o przyszłym kodzie, aby uniknąć tej złej praktyki. Jeśli masz wiele list rozwijanych, po prostu masz wiele właściwości 'IEnumerable ' w swoim modelu widoku. Odnośnie 'return View (studydefinition)', jest to właściwy sposób przekazywania modeli widoków do widoków. Po trzecie, metoda rozszerzenia "DropDownListFor" jest zdefiniowana w przestrzeni nazw 'System.Web.Mvc.Html', więc po prostu dodaj do tej przestrzeni nazw opcję znajdującą się na górze pliku zawierającego pomocnika" DropDownListForSorted "w celu dostosowania go do zakresu . –

0

Jeśli używasz bazy danych można użyć kwerendy, aby zdefiniować element Sortuj

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

Wystarczy dodaj sortowanie, zanim zwrócisz pozycje do listy rozwijanej.

Wykonaj:

Modele: StudyViewModel.cs

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

Kontroler: 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(); 
    } 
} 

Widok: 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() : "") 
) 

W ten sposób unikniesz ViewBags i po prostu użyjesz funkcji do bezpośredniego wypełnienia wartości.

Powiązane problemy