ASP.NET MVC DropDownList自动化填充指南

ASP.NET MVC应用程序开发中,经常需要处理与数据库中外键关联的下拉列表(DropDownList)。通常情况下,开发者会使用Html.DropDownList(...)或Html.DropDownListFor(...)辅助方法,并在控制器中从数据存储中提取数据项,然后将其放入ViewData或ViewBag中,最后在辅助方法中使用这些值。本文将介绍一种通过自定义属性和过滤器来自动化这一过程的方法。

几乎所有的编辑视图模型(EditViewModel)至少需要一个DropDownList来处理模型或数据库中的外键。ASP.NET MVC程序员几乎都会使用Html.DropDownList(...)或Html.DropDownListFor(...)辅助方法。为了填充这个DropDownList,他们会从控制器中的数据存储拉取项目,并将它们放入ViewData或ViewBag,然后在辅助方法中使用这些值。但是,现在将使用一个编辑器模板(EditorTemplate)来处理应用程序中的所有DropDownLists。

代码示例

目标是创建一个通用的DropDownList编辑器模板。首先,定义一个带有DropDown属性的视图模型类:

public class PersonEditor { public int Id { get; set; } public string Name { get; set; } [DropDown("GetServices", 1)] public int? ServiceId { get; set; } }

然后,在控制器中处理这个导航属性,并在视图执行之前传递任何添加的参数:

[FillDropDowns] public ActionResult Edit() { var viewModel = new PersonEditor { ServiceId = 3 }; return View(viewModel); }

需要一个属性来装饰导航属性,并需要一个在视图渲染之前执行的动作过滤器(ActionFilter),以填充ViewData字典中的项。

DropDownList服务层

假设有一个简单的DropDownList服务层:

public class DropDownListService { // ... public IEnumerable GetServices(int typeId) { return context.Services .Where(m => m.Type == typeId) .Select(m => new SelectListItem { Text = m.Name, Value = m.Id.ToString() }); } }

然后,需要在视图渲染之前调用GetServices方法,并将结果存储在某个ViewData键中,以便在视图中检索。

DropDownAttribute

接下来,定义一个自定义属性DropDownAttribute,它继承自UIHintAttribute,以便获取编辑器模板的名称。还需要服务类型,它将为提供IEnumerable,并且有一个重写的构造函数用于默认服务类型。

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)] public class DropDownAttribute : UIHintAttribute { private readonly Type _serviceType; private readonly string _methodName; private readonly object[] _arguments; public DropDownAttribute(string methodName, params object[] arguments) : this(methodName, "DropDown", typeof(DropDownListService), arguments) { } public DropDownAttribute(string methodName, string templateName, Type serviceType, params object[] arguments) : base(templateName) { _serviceType = serviceType; _comboBoxServiceMethods = methodName; _arguments = arguments; } public IEnumerable GetMethodResult() { if (_serviceType == null) throw new NoNullAllowedException("Service class type is needed."); try { var serviceInstance = Activator.CreateInstance(_serviceType); var methodInfo = _serviceType.GetMethod(_methodName); return methodInfo.Invoke(serviceInstance, _arguments) as IEnumerable; } catch (Exception) { throw; } } }

这个属性类定义了需要的方法名和参数,并且添加了params关键字,以便按需传递参数。GetMethodResult方法将由ActionFilter调用以执行并获取结果。

动作过滤器(ActionFilter)

接下来,定义一个动作过滤器FillDropDowns,它将在结果执行时查找视图模型中所有带有DropDownAttribute的属性,并在ViewData字典中填充这些列表。

public class FillDropDowns : ActionFilterAttribute { public override void OnResultExecuting(ResultExecutingContext filterContext) { var viewModel = filterContext.Controller.ViewData.Model; if (viewModel != null) setLists(viewModel.GetType(), filterContext.Controller.ViewData); base.OnResultExecuting(filterContext); } private static void setLists(Type viewModelType, IDictionary viewData) { foreach (var property in viewModelType.GetProperties()) { if (!(property.PropertyType.IsClass && !(property.PropertyType == typeof(string)))) { var att = (DropDownAttribute)GetCustomAttribute(property, typeof(DropDownAttribute)); if (att != null) { var viewDataKey = "DDKey_" + property.Name; viewData[viewDataKey] = viewData[viewDataKey] ?? att.GetMethodResult(); } } else { setLists(property.PropertyType, viewData); } } } }

动作过滤器会检查ViewModel中的属性是否带有DropDownAttribute,并在ViewData字典中填充这些列表。如果已经存在,则不会重复填充。

编辑器模板(EditorTemplate)

最后,需要在EditorTemplates文件夹中添加一个新的视图,作为所有DropDown导航属性的编辑器。由于属性带有UIHintAttribute,所以编辑器模板文件应该命名为"DropDown"。以下是它的简单代码:

@model object @Html.DropDownListFor(m => m, Html.GetAutomatedList(m => m).SetSelected(Model))

接下来,需要两个帮助方法来完成工作:

HTML扩展帮助方法

需要两个帮助方法来获取工作完成:

public static class HtmlExtensions { public static IEnumerable SetSelected(this IEnumerable selectList, object selectedValue) { selectList = selectList ?? new List(); if (selectedValue == null) return selectList; var vlaue = selectedValue.ToString(); return selectList.Select(m => new SelectListItem { Selected = string.Equals(vlaue, m.Value), Text = m.Text, Value = m.Value }); } public static IEnumerable GetAutomatedList(this HtmlHelper htmlHelper, Expression> expression) { var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); return ((IEnumerable)htmlHelper.ViewData["DDKey_" + metadata.PropertyName]); } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485