asp.net – 用于DropDownList的MVC2 EditorTemplate

我在过去一周的大部分时间里都用到了MVC2的新模板功能。我很难试图让一个DropDownList模板工作。我一直在努力解决的最大问题是如何获取下拉列表的源数据到模板。我看到很多例子,您可以将源数据放在ViewData字典(ViewData [“DropDownSourceValuesKey”])中,然后在模板本身中检索它们(var sourceValues = ViewData [“DropDownSourceValuesKey”];)这有效,但是我做了不像一个愚蠢的字符串作为这个工作的lync引脚。

以下是我提出的一种方法,并希望对这种方法提出意见:

这是我的设计目标:

>视图模型应包含下拉列表的源数据
>限制Sil弦
>不使用ViewData字典
>控制器负责使用下拉列表的源数据填充属性

这是我的查看型号:

public class CustomerViewModel
    {
        [ScaffoldColumn(false)]
        public String CustomerCode{ get; set; }

        [UIHint("DropDownList")]
        [DropDownList(DropDownListTargetProperty = "CustomerCode"]
        [DisplayName("Customer Code")]
        public IEnumerable<SelectListItem> CustomerCodeList { get; set; }

        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String PhoneNumber { get; set; }
        public String Address1 { get; set; }
        public String Address2 { get; set; }
        public String City { get; set; }
        public String State { get; set; }
        public String Zip { get; set; }
    }

我的视图模型具有CustomerCode属性,它是用户从值列表中选择的值。我有一个CustomerCodeList属性,它是可能的CustomerCode值的列表,并且是下拉列表的来源。我已经使用DropDownListTargetProperty创建了一个DropDownList属性。 DropDownListTargetProperty指向将根据生成的下拉列表中的用户选择(在本例中为CustomerCode属性)填充的属性。

请注意,CustomerCode属性具有[ScaffoldColumn(false)],这迫使发生器跳过生成的输出中的字段。

我的DropDownList.ascx文件将生成一个来自CustomerCodeList属性的源数据的下拉列表表单元素。生成的下拉列表将使用DropDownList属性中的DropDownListTargetProperty的值作为Id和Select表单元素的Name属性。所以生成的代码将如下所示:

<select id="CustomerCode" name="CustomerCode">
  <option>...
</select>

这样做非常好,因为在提交表单时,MVC将从下拉列表中选择所需值填充目标属性,因为生成的下拉列表的名称是目标属性。我有点可视化,因为CustomerCodeList属性是CustomerCode属性的扩展。我将源数据与资源相结合。

这是我的控制器代码:

public ActionResult Create()
{
    //retrieve CustomerCodes from a datasource of your choosing
    List<CustomerCode> customerCodeList = modelService.GetCustomerCodeList();

    CustomerViewModel viewModel= new CustomerViewModel();
    viewModel.CustomerCodeList = customerCodeList.Select(s => new SelectListItem() { Text = s.CustomerCode,Value = s.CustomerCode,Selected = (s.CustomerCode == viewModel.CustomerCode) }).AsEnumerable();

    return View(viewModel);
}

这是我的DropDownListAttribute的代码:

namespace AutoForm.Attributes
{
    public class DropDownListAttribute : Attribute
    {
        public String DropDownListTargetProperty { get; set; }
    }
}

这是我的模板代码(DropDownList.ascx):

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<SelectListItem>>" %>
<%@ Import Namespace="AutoForm.Attributes"%>

<script runat="server">
    DropDownListAttribute GetDropDownListAttribute()
    {
        var dropDownListAttribute = new DropDownListAttribute();

        if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("DropDownListAttribute"))
        {
            dropDownListAttribute = (DropDownListAttribute)ViewData.ModelMetadata.AdditionalValues["DropDownListAttribute"];
        }

        return dropDownListAttribute;        
    }
</script>    

<% DropDownListAttribute attribute = GetDropDownListAttribute();%>

<select id="<%= attribute.DropDownListTargetProperty %>" name="<%= attribute.DropDownListTargetProperty %>">
    <% foreach(SelectListItem item in ViewData.Model) 
       {%>
        <% if (item.Selected == true) {%>
            <option value="<%= item.Value %>" selected="true"><%= item.Text %></option>
        <% } %>
        <% else {%>
            <option value="<%= item.Value %>"><%= item.Text %></option>
        <% } %>
    <% } %>
</select>

我尝试使用Html.DropDownList帮助器,但是不允许我更改生成的Select元素的Id和Name属性。

注意:您必须覆盖DropDownListAttribute的DataAnnotationsModelMetadataProvider的CreateMetadata方法。这是代码:

public class MetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes,Type containerType,Func<object> modelAccessor,Type modelType,string propertyName)
    {
        var metadata = base.CreateMetadata(attributes,containerType,modelAccessor,modelType,propertyName);
        var additionalValues = attributes.OfType<DropDownListAttribute>().FirstOrDefault();

        if (additionalValues != null)
        {
            metadata.AdditionalValues.Add("DropDownListAttribute",additionalValues);
        }

        return metadata;
    }
}

那么你必须在Global.asax.cs的Application_Start中调用新的MetadataProvider:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);

    ModelMetadataProviders.Current = new MetadataProvider();
}

那么,我希望这是有道理的,我希望这种方法可以节省你一些时间。我想要一些关于这种方法的反馈。有更好的方法吗?

解决方法

我想我找到一个解决方案,使其工作时使用Html.EditorForModel();当使用EditorForModel()时,MVC使用Object.ascx循环遍历模型的所有属性,并为模型中的每个属性调用相应的模板。 ASP.Net MVC开箱即用的Object.ascx在代码中,但您可以创建自己的Object.ascx。只需在“共享视图”文件夹中创建一个EditorTemplates子文件夹。在那里创建一个Object.ascx文件(阅读这篇文章了解更多信息: http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html)

这是我的Object.ascx:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%@ Import Namespace="WebAppSolutions.Helpers" %>
<% if (ViewData.TemplateInfo.TemplateDepth > 1) { %>
<%= ViewData.ModelMetadata.SimpleDisplayText%>
<% }
else { %>    
<% foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForEdit && !ViewData.TemplateInfo.Visited(pm))) { %>

    <% var htmlFieldName = Html.HtmlFieldNameFor(prop.PropertyName);%>

    <% if (prop.HideSurroundingHtml) { %>
        <%= Html.Editor(htmlFieldName)%>
    <% }
       else { %>
        <div id="<%= htmlFieldName %>Container" class="editor-field">
            <% if (!String.IsNullOrEmpty(Html.Label(prop.PropertyName).ToHtmlString())) { %>
                <%= Html.Label(prop.PropertyName,Html.HtmlDisplayName(prop.PropertyName),prop.IsRequired)%>
            <% } %>
            <%= Html.Editor(prop.PropertyName,"",htmlFieldName)%>
            <%= Html.ValidationMessage(prop.PropertyName,"*") %>
        </div>
    <% } %>
<% } %>

<%}%>

我的WebAppSolutions.Helpers中有一些托管代码用于HtmlFieldNameFor和HtmlDisplayName。这些帮助程序从应用于视图模型中的属性的属性中检索数据。

public static String HtmlFieldNameFor<TModel>(this HtmlHelper<TModel> html,String propertyName)
    {
        ModelMetadata modelMetaData = GetModelMetaData(html,propertyName);
        return GetHtmlFieldName(modelMetaData,propertyName);
    }

    public static String HtmlDisplayName<TModel>(this HtmlHelper<TModel> html,propertyName);
        return modelMetaData.DisplayName ?? propertyName;
    }
    private static ModelMetadata GetModelMetaData<TModel>(HtmlHelper<TModel> html,String propertyName)
    {
        ModelMetadata modelMetaData = ModelMetadata.FromStringExpression(propertyName,html.ViewData);
        return modelMetaData;
    }

    private static String GetHtmlFieldName(ModelMetadata modelMetaData,string defaultHtmlFieldName)
    {
        PropertyExtendedMetaDataAttribute propertyExtendedMetaDataAttribute = GetPropertyExtendedMetaDataAttribute(modelMetaData);
        return propertyExtendedMetaDataAttribute.HtmlFieldName ?? defaultHtmlFieldName;
    }

使用EditorModelFor()得到这个工作的关键是这个(在上面的Object.ascx中应该是第20行):

<%= Html.Editor(prop.PropertyName,htmlFieldName)%>

prop.PropertyName是ViewModel中的属性,包含将成为DropDownList的数据列表。 htmlFieldName是DropDownList属性替换隐藏的属性的名称。合理?

我希望这可以帮助你。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


判断URL文件是不是在于在。private static bool UrlIsExist(string url){ System.Uri u = null; try { u = new Uri(url); } catch { return false; } bool isExist = false;
由于在.net中,Request时出现有HTML或Javascript等字符串时,系统会认为是危险性值。立马报错。解决方案一:在.aspx文件头中加入这句:解决方案二:修改web.config文件:因为validateRequest默认值为true。只要设为false即可。
public static bool ProcessIdCard(this string idCard, out DateTime birthday, out string genderName) { bool result; birthda...
如果你在GridView控件上设置 AllowPaging=&quot;true&quot; or AllowSorting=&quot;true&quot; 而没有使用使用数据源控件 DataSource (i.e. SqlDataSource, ObjectDataSource),运行则会出现下
protected void Page_Load(object sender, EventArgs e){ ScriptManager sm = Page.Master.FindControl(&quot;ScriptManager1&quot;) as ScriptManager; if (sm
1. install all features in IIS2. Try the following steps to register it.run %windir%\Microsoft.NET\Framework\v4.0.21006\aspnet_regiis.exe -i或运行,跳出如下错误
一般来说一个 HTML 文档有很多标签,比如“”、“”、“”等,想把文档中的 img 标签提取出来并不是一件容易的事。由于 img 标签样式变化多端,使提取的时候用程序寻找并不容易。于是想要寻找它们就必须写一个非常健全的正则表达式,不然有可能会找得不全,或者找出来的不是正确的 img 标签。我们可以
asp.net updatepanel 局部刷新,导致JS不能加载,而无法使用,而且 updatepanel会刷两次,郁闷的。解决方法如下:
FileHandlerhttp://www.cnblogs.com/vipsoft/p/3627709.htmlUpdatePanel无法导出下载文件:http://www.cnblogs.com/vipsoft/p/3298299.html//相对路径下载。path: ~/DownLoad///p
本地能上传文件,部署到服务器上就报Cannot access a closed file 错误,以下是解决方法: 最重要是requestLengthDiskThreshold此属性设置输入流缓冲阈值。
http://tool.oschina.net/commons字符十进制转义字符&quot;&amp;#34;&amp;quot;&amp;&amp;#38;&amp;amp;&amp;#62;&amp;gt;不断开空格(non-breaking space)&amp;#160;HTML特殊转义字符
1、2两步为推荐做法1. 将MySql.Data.dll放到 bin目录下面,或都安装mysql-connector-net-6.0.0.msi2.web.config 添加如下节点,注册版本号一致 3.全局配置在C:\WINDOWS\Microsoft.NET\Framework\v2.0.507
C# 跳转新页面string url = &quot;http://www.vipsoft.com.cn&quot;;ResponseRedirect.Redirect(Response, url, &quot;_blank&quot;, &quot;&#39;toolbar=0,scrollbar
.NET Core 在其上下文中,该请求的地址无效。 看了端口,发现没被占用,后来发现是IP地址变了 改成正确的IP就可以了。
datatable是一个jquery扩展的表格插件。其提供了强大的表格功能。官方地址:http://www.datatables.net/在官方示例中,对于表格的是否可排序是在初始化中设置的一个值来决定的$(&quot;.datatable-simplified&quot;).dataTable(
Html table 细边框 导航页档 军事 历史 ...
C# 跳转新页面判断URL文件是不是在于在。C# 指定物理目录下载文件,Response.End导致“正在中止线程”异常的问题public class FileHandler { public static bool DownLoadFile(string path, string fileName
由于将IE11升级到了 11 之前的网站无法正常使用,如果是开发人员碰到之问题,使用了微软的asp.net 控件,那么将服务器的.net framework 升级到 4.5http://www.microsoft.com/en-us/download/details.aspx?id=30653如果浏
引言 本文从Linux小白的视角, 在CentOS 7.x服务器上搭建一个Nginx-Powered AspNet Core Web准生产应用。 在开始之前,我们还是重温一下部署原理,正如你所常见的.Net Core 部署图: 在Linux上部署.Net Core App最好的方式是在Linux机器