Several views from my project have the same dropdownlist...
So, in the ViewModel from that view I have :
public IEnumerable Fo
I'd say that's fine to be honest, as it's only a repeat of a few lines of code. If it's really bothering you though, you could have all your controllers inherit from a BaseController
(if they don't already) and store a method in there to get them all, something like:
public IEnumerable<SelectListItem> GetFoos()
{
return fooRepository.GetAll().ToSelectList(x => x.Id, x => x.Name);
}
Then in your controllers you could do:
var MyVM = new MyVM() {
FooDdl = GetFoos()
}
If you really don't want to duplicate the code, place the code from the controllers into a helper class, and render the dropdown within a shared view (like _Layout.cshtml) that you'd then have to implement into your views by RenderPartial.
Create a partial view, _MyDropdownView.cstml, which uses the helper class you threw the code from the controllers in with something like the following:
@using MyNamespace.MyHelperClass
<div id="myDropdown">@Html.DropDownListFor(model => model.Prop, MyVM as SelectList, "--Select a Property--")</div>
Then, within your views:
@Html.RenderPartial("_MyDropdownView")
We also use a static class :
public static class SelectLists
{
public static IList<SelectListItem> CompanyClasses(int? selected)
{
var session = DependencyResolver.Current.GetService<ISession>();
var list = new List<SelectListItem>
{
new SelectListItem
{
Selected = !selected.HasValue,
Text = String.Empty
}
};
list.AddRange(session.All<CompanyClass>()
.ToList()
.OrderBy(x => x.GetNameForCurrentCulture())
.Select(x => new SelectListItem
{
Selected = x.Id == (selected.HasValue ? selected.Value : -1),
Text = x.GetNameForCurrentCulture(),
Value = x.Id.ToString()
})
.ToList());
return list;
}
}
In the view we have nothing special :
@Html.DropDownListFor(x => x, SelectLists.CompanyClasses(Model))
And sometime we also create an EditorTemplate so it's faster to reuse like this
Model :
[Required, UIHint("CompanyClassPicker")]
public int? ClassId { get; set; }
EditorTemplate :
@model int?
@if (ViewBag.ReadOnly != null && ViewBag.ReadOnly)
{
var item = SelectLists.CompanyClasses(Model).FirstOrDefault(x => x.Selected);
if (item != null)
{
<span>@item.Text</span>
}
}
else
{
@Html.DropDownListFor(x => x, SelectLists.CompanyClasses(Model))
}
Create object with getter for your dropdown values:
public static class DropDowns
{
public static List<SelectListItem> Items {
get
{
//Return values
}
}
}
Create Razor partial:
@Html.DropDownListFor(m => "ChoosenItem", DropDowns.Items, "")
Call partial:
@Html.RenderPartial("DropDownItems")
And finally receive ChoosenItem value in controller. Simply.
I like to use static classes often in a helper class that I can call from any view.
@Html.DropDownListFor(x => x.Field, PathToController.GetDropDown())
and then in your controller have a method built like this
public static List<SelectListItem> GetDropDown()
{
List<SelectListItem> ls = new List<SelectListItem>();
lm = (call database);
foreach (var temp in lm)
{
ls.Add(new SelectListItem() { Text = temp.name, Value = temp.id });
}
return ls;
}
Hopefully it helps.
Extension methods to the rescue
public interface ISelectFoo {
IEnumerable<SelectListItem> FooDdl { get; set; }
}
public class FooModel:ISelectFoo { /* implementation */ }
public static void PopulateFoo(this ISelectFoo data, FooRepository repo)
{
data.FooDdl = repo.GetAll().ToSelectList(x => x.Id, x => x.Name);
}
//controller
var model=new ViewModel();
model.PopulateFoo(repo);
//a wild idea
public static T CreateModel<T>(this FooRepository repo) where T:ISelectFoo,new()
{
var model=new T();
model.FooDdl=repo.GetAll().ToSelectList(x => x.Id, x => x.Name);
return model;
}
//controller
var model=fooRepository.Create<MyFooModel>();