ASP.MVC 3 Razor Add Model Prefix in the Html.Parti

2019-01-19 17:53发布

问题:

I have all most the same question as him ASP.NET MVC partial views: input name prefixes

I am tring to create CRUD operations for this data entities:

public class UserViewModel 
{  
   protected virtual Id {get; set;} 
   public virtual string Login { get; set; }
   public virtual string Password { get; set; }
   public virtual ZipCodeViewModel ZipCode { get; set; }
}

Zip Code entity:

public class ZipCodeViewModel
{        
   public virtual string City { get; set; }

   public virtual string State { get; set; }           

   public virtual string Zip { get; set; }
}

I also have partial view ZipCode which used UserViewModel.ZipCode:

@model ZipCodeViewModel    

    @Html.TextBoxFor(x => x.Zip, new { id = "ZipCode", name = "ZipCode.Zip", maxlength = "5" })     

I am going to use ZipCodePartialView in another Page (for example user).

@model UserViewModel
.....
@{Html.RenderPartial("Zipcode", Model.ZipCode);}

When MVC save User ZipCode field Zip is empty.

So question is how I can add model prefix to the patrial View?

回答1:

Try this extension:

public static void RenderPartialWithPrefix(this HtmlHelper helper, string partialViewName, object model, string prefix)
        {
            helper.RenderPartial(partialViewName,
                                 model,
                                 new ViewDataDictionary { TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = prefix } });
        }


回答2:

Instead of using Html.RenderPartial() put your partial view in Shared/EditorTemplates/ and name it the name of the type (in this case ZipCodeViewModel). Then you can use Html.EditorFor() passing in the expression for the property. EditorFor() prefixes the fields correctly so that the model binder in MVC can put your data in place correctly.

So something like this

@model UserViewModel
.....
@Html.EditorFor(m => m.ZipCode);

I'll try to dig up some links and resources but wanted to get the answer out there for you.

EDIT: This blog post seems to go over the basics of EditorFor() extension and EditorTempaltes: Quick Tips About ASP.NET MVC: Editor Tempaltes

Anyway, when you use those Html.TextBoxFor() or Html.DropDownFor() extensions, what they do is get the full name of the property from the expression you pass in and set the HTML input element's name and id attributes to that. Example could be:

@Html.TextBoxFor(m => m.Person.FirstName)

would render

<input id="Person_FirstName" name="Person.FirstName" type="text" value="<what ever was in FirstName>" />

Those input names and values are the key/value pairs in the post data. The default ASP.NET MVC model binder tries to match those keys up to the models your controller actions take in. If it can find a match then it sets the value.

So your problem above is probably because the input names in your partial view are from the ZipCodeViewModel down but your action is taking in a UserViewModel. The EditorFor() prefixes the names for you so it can basically render a partial view that will post data back that can be bound for you. Although you could set the name attributes yourself on the input elements (or flatten everything as you suggested in the comments) has these helpers in there to do it for you.

I hope that helps explain what is happening and a possible solution for you.



回答3:

As it turns out EditorTemplates is the way to go. (first comment on this post: http://thatextramile.be/blog/2011/01/prefixing-input-elements-of-partial-views-with-asp-net-mvc)

Simply add ZipCodeViewModel.cshtml to an EditorTemplates folder, which can sit inside Views/Shared if you want. Then use, @Html.EditorFor(m => m.ZipCode). Works like magic.



回答4:

You can the following code:

ActionResult MyAction(UserViewModel model)
{
    TryUpdateModel(model.ZipCode);
}

So model well be updated twice. Second time for your partial.