I’m asked quite a bit how to bind a dropdown list in ASP.NET MVC. So there are about 10,000 ways to do it, but here’s one.
First, we’ll create a simple interface to return a list of SelectListItem so we can use the built-in DropDownListFor() later on.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface ISelectListProvider | |
{ | |
IEnumerable<SelectListItem> Provide(); | |
} |
Then we can create a SelectListProviderAttribute to take in the Type of list provider we want. You can see in this example I'm instantiating the object with StructureMap...you could do this with Activator or something else.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] | |
public class SelectListProviderAttribute : Attribute | |
{ | |
public ISelectListProvider Provider { get; private set; } | |
public SelectListProviderAttribute(Type providerType) | |
{ | |
if (typeof(ISelectListProvider).IsAssignableFrom(providerType)) | |
{ | |
Provider = (ISelectListProvider) ObjectFactory.GetInstance(providerType); | |
} | |
else | |
{ | |
throw new ArgumentException("Provider type must be of type ISelectListProvider", "providerType"); | |
} | |
} | |
} |
Now we just implement an ISelectListProvider and add the attribute to our model like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class CommunitySelectListProvider : ISelectListProvider | |
{ | |
private readonly IGetCommunitiesQuery _getCommunitiesQuery; | |
public CommunitySelectListProvider(IGetCommunitiesQuery getCommunitiesQuery) | |
{ | |
_getCommunitiesQuery = getCommunitiesQuery; | |
} | |
public IEnumerable<SelectListItem> Provide() | |
{ | |
var communities = _getCommunitiesQuery.Execute(); | |
return communities.Select(community => new SelectListItem { Text = community.Name, Value = community.CommunityId.ToString() }).ToList(); | |
} | |
} |
Sample property on view model:
[SelectListProvider(typeof(CommunitySelectListProvider))]Now we just call our new HtmlHelper in our view and we're done. So here's the helper:
[DisplayName("Community")]
public int CommunityId { get; set; }
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression) where TModel : class | |
{ | |
var property = expression.GetProperty(); | |
IEnumerable<SelectListItem> selectList; | |
var selectListProviderAttribute = property.GetAttribute<SelectListProviderAttribute>(); | |
if (selectListProviderAttribute != null) | |
{ | |
var provider = selectListProviderAttribute.Provider; | |
selectList = provider.Provide(); | |
} | |
else | |
{ | |
throw new ArgumentException(string.Format("SelectListProvider not specified for property \"{0}\"", property.Name)); | |
} | |
return html.DropDownListFor(expression, selectList); | |
} |
And now we just call it from the view like this:
@Html.DropDownListFor(x => x.CommunityId)
I'm sure you all realized that I used some additional helpers in code samples above. So for the curious few, I uploaded the full sample project to github. Browse the source now