ASP.NET MVC 2 - ViewModel Prefix

2019-03-25 08:41发布

问题:

I want to use RenderPartial twice in my view with different models associated. The problem is that some properties are present in both models (nickname, password). They have no prefix, so even the id's or names are equal in the output. Now, if I have model errors for nickname or password, both fields get highlighted.

Main View:

<div>
    <% Html.RenderPartial("Register", Model.RegisterModel); %>
</div>
<div>
    <% Html.RenderPartial("Login", Model.LoginModel); %>
</div>

Login PartialView:

<% using (Html.BeginForm("Login", "Member")) { %>
<fieldset>
    <legend>Login</legend>
    <p>
        <%= Html.LabelFor(x => x.Nickname) %>
        <%= Html.TextBoxFor(x => x.Nickname) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Password) %>
        <%= Html.PasswordFor(x => x.Password) %>
    </p>    
    <input type="submit" value="Login" />
</fieldset>
<% } %>

Register PartialView:

<% using (Html.BeginForm("Register", "Member")) { %>
<fieldset>
    <legend>Register</legend>
    <p>
        <%= Html.LabelFor(x => x.Nickname) %>
        <%= Html.TextBoxFor(x => x.Nickname) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Email) %>
        <%= Html.TextBoxFor(x => x.Email) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Password) %>
        <%= Html.PasswordFor(x => x.Password) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.PasswordRepeat) %>
        <%= Html.PasswordFor(x => x.PasswordRepeat) %>
    </p>
    <input type="submit" value="Register" />
</fieldset>
<% } %>

How can I change this?

回答1:

Instead of using Html.RenderPartial you could use editor templates which will handle prefixes.

So in your main view:

<div>
    <%-- See below what does the second argument mean --%>
    <%= Html.EditorFor(x => x.RegisterModel, "RegisterModel") %>
</div>
<div>
    <%= Html.EditorFor(x => x.LoginModel, "LoginModel") %>
</div>

And then create a folder Views/Shared/EditorTemplates/RegisterModel.ascx (The name of this file is used in the EditorFor helper method). Also notice that this partial should be strongly typed to the type of the RegisterModel property:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Ns.Models.RegisterModel>" %>

<% using (Html.BeginForm("Register", "Member")) { %>
<fieldset>
    <legend>Register</legend>
    <p>
        <%= Html.LabelFor(x => x.Nickname) %>
        <%= Html.TextBoxFor(x => x.Nickname) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Email) %>
        <%= Html.TextBoxFor(x => x.Email) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Password) %>
        <%= Html.PasswordFor(x => x.Password) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.PasswordRepeat) %>
        <%= Html.PasswordFor(x => x.PasswordRepeat) %>
    </p>
    <input type="submit" value="Register" />
</fieldset>
<% } %>

You could define a different partial for the login model in Views/Shared/EditorTemplates/LoginModel.ascx



回答2:

If you can't do an EditorTemplate for some reason, you can do this in your View:

var dataDict = new ViewDataDictionary();
dataDict.TemplateInfo.HtmlFieldPrefix = "myPrefixHere";
Html.RenderPartial("myPartialViewName", myPartialViewModel, dataDict);

Lo and behold, all inputs in your PartialView will be prefixed.

Kudos to R0MANARMY for pointing this out.



回答3:

Looks like there's an overload for TextBoxFor that allows you to specify extra HTML attributes. It isn't an ideal solution, but it should let you change the id (and possibly name?) of the rendered textboxes. Of course changing the name would probably screw things up when you try to post the form.



回答4:

First of all, you could use Html.TextBox("input form name", ...) and set the name to whatever you wish. There's a bigger issue how would you provide a prefix on Html.RenderPartial() level? You are already providing a model instance. So without changing their view models, there's just one more possibility: to write your own overloads for RenderPartial() that would take the prefix and pass it on to others.

Check this one out. Someone's written a whole bunch of overloads that support setting prefixes. TextBoxFor rendering to HTML with prefix on the ID attribute

If any is missing you can see the pattern how to extend these with additional ones you may need.