MVC2 EditorTemplate为DropDownList的 [英] MVC2 EditorTemplate for DropDownList

查看:165
本文介绍了MVC2 EditorTemplate为DropDownList的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经花费了多数在过去一周膝盖深烘焙到MVC2新的模板功能。我有一个很难试图让一个DropDownList模板工作。我一直在努力解决的最大问题是如何获取源数据下拉列表中的模板。我看到了很多的例子,你可以把源数据的ViewData字典(计算机[DropDownSourceValues​​Key])然后在模板本身(VAR sourceValues​​ =计算机[DropDownSourceValues​​Key];)检索它们这工作,但我没有不喜欢有一个愚蠢的字符串作为林奇引脚使这项工作。

I've spent the majority of the past week knee deep in the new templating functionality baked into MVC2. I had a hard time trying to get a DropDownList template working. The biggest problem I've been working to solve is how to get the source data for the drop down list to the template. I saw a lot of examples where you can put the source data in the ViewData dictionary (ViewData["DropDownSourceValuesKey"]) then retrieve them in the template itself (var sourceValues = ViewData["DropDownSourceValuesKey"];) This works, but I did not like having a silly string as the lynch pin for making this work.

下面是一个办法,我拿出并希望得到这一做法的意见:

Below is an approach I've come up with and wanted to get opinions on this approach:

下面是我的设计目标:


  • 视图模型应该包含源数据的下拉列表

  • 限制傻字符串

  • 不使用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; }
    }

我的视图模型有一个客户code属性是一个值,用户从值列表中进行选择。我有一个客户codeLIST属性,它是可能的客户code值的列表,是一个下拉列表中选择来源。我创建了一个DropDownListTargetProperty一个DropDownList属性。 DropDownListTargetProperty指向属性将要基于从所生成的下拉(在此情况下,客户code属性)用户选择填充。

My View Model has a CustomerCode property which is a value that the user selects from a list of values. I have a CustomerCodeList property that is a list of possible CustomerCode values and is the source for a drop down list. I've created a DropDownList attribute with a DropDownListTargetProperty. DropDownListTargetProperty points to the property which will be populated based on the user selection from the generated drop down (in this case, the CustomerCode property).

的通知的客户code酒店[ScaffoldColumn(假),迫使发电机跳过生成的输出领域。

Notice that the CustomerCode property has [ScaffoldColumn(false)] which forces the generator to skip the field in the generated output.

我DropDownList.ascx文件将生成与客户codeLIST财产来源的数据下拉列表表单元素。生成的下拉列表将使用DropDownListTargetProperty的值从DropDownList的属性作为ID和选择表单元素的名称属性。因此,产生的code将是这样的:

My DropDownList.ascx file will generate a dropdown list form element with the source data from the CustomerCodeList property. The generated dropdown list will use the value of the DropDownListTargetProperty from the DropDownList attribute as the Id and the Name attributes of the Select form element. So the generated code will look like this:

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

这工作了很大,因为提交表单的时候,MVC将会从下拉列表填充所选值目标属性,因为生成的下拉列表的名称的 target属性。我有点想象它作为客户codeLIST属性为各种客户code属性的延伸。我已经加上源数据的属性。

This works out great because when the form is submitted, MVC will populate the target property with the selected value from the drop down list because the name of the generated dropdown list IS the target property. I kinda visualize it as the CustomerCodeList property is an extension of sorts of the CustomerCode property. I've coupled the source data to the property.

这里是我的code为控制器:

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

这里是我的code为DropDownListAttribute:

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

这里是我的code为模板(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帮手,但它不会让我改变了Id和生成的选择元素的名称属性。

I tried using the Html.DropDownList helper, but it would not allow me to change the Id and Name attributes of the generated Select element.

请注意:你必须覆盖DataAnnotationsModelMetadataProvider为DropDownListAttribute的CreateMetadata方法。这里的code为:

NOTE: you have to override the CreateMetadata method of the DataAnnotationsModelMetadataProvider for the DropDownListAttribute. Here's the code for that:

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呼叫:

Then you have to make a call to the new MetadataProvider in Application_Start of Global.asax.cs:

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

    ModelMetadataProviders.Current = new MetadataProvider();
}

嗯,我希望这是有道理的,我希望这种方式可以节省你一些时间。我想一些反馈这种方法吧。有没有更好的方法吗?

Well, I hope this makes sense and I hope this approach may save you some time. I'd like some feedback on this approach please. Is there a better approach?

推荐答案

我想我找到了一个解决方案,以使用Html.EditorForModel时(它的工作);当使用EditorForModel(),MVC使用Object.ascx遍历模型的所有特性,并要求在模型中的每个属性相应的模板。 ASP.Net MVC开箱具有Object.ascx在code,但你可以创建自己的Object.ascx。只要创建你的共享文件夹视图的EditorTemplates子文件夹。创建Object.ascx文件存在。 (阅读这篇文章的详细资料:<一href=\"http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html\" rel=\"nofollow\">http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html)

I think I found a solution to make it work when using Html.EditorForModel(); When using EditorForModel(), MVC uses Object.ascx to loop through all properties of the model and calls the corresponding template for each property in the model. ASP.Net MVC out of the box has Object.ascx in code, but you can create your own Object.ascx. Just create an EditorTemplates subfolder in your Shared View folder. Create an Object.ascx file there. (read this post for more information: http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html)

下面是我的Object.ascx:

Here's my 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>
    <% } %>
<% } %>

&LT;%}%>

<% } %>

我在我的WebAppSolutions.Helpers为HtmlFieldNameFor和HtmlDisplayName一些custome code。这些助手从视图模型应用到物业属性检索数据。

I have some custome code in my WebAppSolutions.Helpers for HtmlFieldNameFor and HtmlDisplayName. These helpers retrieve data from attributes applied to properties in the view model.

    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, String propertyName)
    {
        ModelMetadata modelMetaData = GetModelMetaData(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()工作的关键是这个(应该是20行左右,Object.ascx以上):

The key to getting this to work using EditorModelFor() is this (should be line 20 or so in Object.ascx above):

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

prop.PropertyName是在视图模型包含的数据的列表中,这将成为DropDownList的财产。 htmlFieldName是的隐藏的DropDownList的属性被替换属性的名称。有意义吗?

prop.PropertyName is the property in the ViewModel containing the list of data that will become the DropDownList. htmlFieldName is the name of the property that's hidden that the DropDownList property is replacing. Make sense?

我希望这可以帮助你。

这篇关于MVC2 EditorTemplate为DropDownList的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆