强类型模型不从部分视图发布

时间:2012-06-05 13:12:37

标签: c# asp.net-mvc-3 asp.net-mvc-partialview strong-typing

我有一个MVC3页面,包含以下组件:

ProfileController - 包含所有操作并加载以下所有视图

/ Profile / Index - 此操作方法创建UserViewModel的实例,其中包含多个属性和嵌套集合,包括一个名为“PrefPrograms”的类型为“ PreferencePrograms,“定义为:

public class PreferencePrograms : List<PreferenceProgram>

“Index”操作方法填充PrefPrograms集合和UserViewModel的其余部分,并将该模型传递到强类型“Index.cshtml”视图中。

Index.cshtml - 这是“UserViewModel”类型的强类型视图。它由多个部分视图组成。此页面中的一个部分视图名为“Preferences.cshtml”,它提供了PrefPrograms集合的格式化显示。 Index.cshtml的相关部分如下。

@model ProfilePreferenceCenterProto.Models.UserViewModel

@{ Html.RenderPartial("Preferences", Model); }

Preferences.cshtml - 这个强类型的局部视图由Index.cshtml使用Html.RenderPartial(上面)加载。在Preferences.cshtml中,我有一个Begin.AjaxForm()方法,用于发布到“PreferenceSubmit”操作,输入提交按钮位于此局部视图的底部。在局部视图中,我调用@Html.EditorFor()帮助程序为“PrefPrograms”集合中的每个“PreferenceProgramModel”项加载编辑器模板。

这是我的问题 - 所有项目都正确加载(包括部分视图和编辑器组件),但是当我将Preferences.cshtml上的表单发布到“PreferencesSubmit”操作时,模型的值不会传递(模型被实例化,但值只是初始化 - 属性和集合值实际上没有传递回控制器。)

Preferences.cshtml部分视图如下所示。

@model ProfilePreferenceCenterProto.Models.UserViewModel

<div id="accordian">
@using(Ajax.BeginForm("PreferencesSubmit", "Profile", new AjaxOptions{ UpdateTargetId = "accordian" })){

  <div id="accordion">

  <ul class="tabs">

  </ul>

  <div class="panes">
  <div> 
  @{
      List<string> AffiliateNames = new List<string>();
      foreach(ProfilePreferenceCenterProto.Models.PreferenceProgramModel list in Model.PrefPrograms)
      {
          AffiliateNames.Add(list.SubcategoryName);
      }

      IEnumerable<string> listNames = AffiliateNames.Distinct();
      int counter = 0;
  }

  @foreach (string AccordionTabName in listNames)
  {
     <h2>@AccordionTabName</h2>
      <div class="pane" @if (counter == 0){ <text>style="display:block;"</text> } >
      <table>
        <tr class="row">
            <th class="name">Subscription</th>
            <th class="icon">Email</th>            
            <th class="icon">SMS</th>
            <th class="icon">Facebook</th>
            <th class="icon">Mail</th>
            <th class="icon">Phone</th>
        </tr>

    @{ 
    counter++;
    var TabPrograms = (from l in Model.PrefPrograms
                       where l.SubcategoryName == @AccordionTabName
                       select l);
    }                              
    @Html.EditorFor(m => TabPrograms)                     
      </table>
      </div>
  }
  </div>

      </div>
    </div>
       <div align="center"><input type="submit" value="Save Preferences" /></div>

}  

/Shared/EditorTemplates/PreferenceProgramModel.cshtml - “PreferenceProgramModel”项目的编辑模板,定义如下:

@model ProfilePreferenceCenterProto.Models.PreferenceProgramModel

<tr class="row">
<td class="name">@Model.ListName</td>                
<td class="icon">
@if (Model.EmailEnabled)
{    
    <a id="@Model.EmailFilterID" href="#" onclick="ImageClick(@Html.IdFor(m => m.EmailStatus));"><img height="25" width="28" src="@Model.Email_Icon_NotSelected" /></a>
}
</td>
<td class="icon">
@if (Model.SMSEnabled)
{
    <a id="@Model.SMSFilterID" href="#"><img height="25" width="28" src="@Model.SMS_Icon_NotSelected" /></a>
}
</td>
<td class="icon">
@if (Model.FBEnabled)
{
    <a id="@Model.FBFilterID" href="#"><img height="25" width="28" src="@Model.FB_Icon_NotSelected" /></a>
}
</td>
<td class="icon">
@if (Model.MailEnabled)
{
    <a id="@Model.MailFilterID" href="#"><img height="25" width="28" src="@Model.Mail_Icon_NotSelected" /></a>
}
</td>
<td class="icon">
@if (Model.PhoneEnabled)
{
    <a id="@Model.PhoneFilterID" href="#"><img height="25" width="28" src="@Model.Phone_Icon_NotSelected" /></a>
}
</td>
</tr>  

@Html.HiddenFor(m => m.EmailStatus)
@Html.HiddenFor(m => m.SMSStatus)
@Html.HiddenFor(m => m.FBStatus)
@Html.HiddenFor(m => m.MailStatus)
@Html.HiddenFor(m => m.PhoneStatus)

<script type="text/javascript">
$(document).ready(function () {

    function ImageClick(Resource) {
        alert(Resource.attr("value"));
        if (Resource.attr("value") != 1) {
            Resource.val("1");
        }
        else {
            Resource.val("2");
        }
        alert(Resource.attr("value"));
    }

    if ("@Model.EmailEnabled" == "True") {
        $("#@Model.EmailFilterID").click(function () {

            ImageClick($("#@Html.IdFor(m => m.EmailStatus)"));
            return false;
        });
    }

    if ("@Model.SMSEnabled" == "True") {
        $("#@Model.SMSFilterID").click(function () {
            ImageClick($("#@Html.IdFor(m => m.SMSStatus)"));
            return false;
        });
    }

    if ("@Model.FBEnabled" == "True") {
        $("#@Model.FBFilterID").click(function () {
            ImageClick($("#@Html.IdFor(m => m.FBStatus)"));
            return false;
        });
    }

    if ("@Model.MailEnabled" == "True") {
        $("#@Model.MailFilterID").click(function () {
            ImageClick($("#@Html.IdFor(m => m.MailStatus)"));
            return false;
        });
    }

    if ("@Model.PhoneEnabled" == "True") {
        $("#@Model.PhoneFilterID").click(function () {
            ImageClick($("#@Html.IdFor(m => m.PhoneStatus)"));
            return false;
        });
    }

});
</script>

使用此签名定义PreferencesSubmit控制器操作:

public ActionResult PreferencesSubmit(Models.UserViewModel model)

页面中呈现的表单标记如下:

<form action="/Profile/PreferencesSubmit" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#accordian" id="form0" method="post"> 

一些渲染的隐藏字段如下所示:

<input data-val="true" data-val-number="The field EmailStatus must be a number." data-val-required="The EmailStatus field is required." id="TabPrograms_0__EmailStatus" name="TabPrograms[0].EmailStatus" type="hidden" value="0" />
<input data-val="true" data-val-number="The field SMSStatus must be a number." data-val-required="The SMSStatus field is required." id="TabPrograms_0__SMSStatus" name="TabPrograms[0].SMSStatus" type="hidden" value="0" />
<input data-val="true" data-val-number="The field FBStatus must be a number." data-val-required="The FBStatus field is required." id="TabPrograms_0__FBStatus" name="TabPrograms[0].FBStatus" type="hidden" value="0" />
<input data-val="true" data-val-number="The field MailStatus must be a number." data-val-required="The MailStatus field is required." id="TabPrograms_0__MailStatus" name="TabPrograms[0].MailStatus" type="hidden" value="0" />
<input data-val="true" data-val-number="The field PhoneStatus must be a number." data-val-required="The PhoneStatus field is required." id="TabPrograms_0__PhoneStatus" name="TabPrograms[0].PhoneStatus" type="hidden" value="0" />

我已经验证了在调用PreferencesSubmit时ModelState.IsValid为true,但模型本身不包含页面中的实际值。 如何在部分视图中将强类型模型值传递回提交时的Action方法?

2 个答案:

答案 0 :(得分:1)

从表单提交的值将根据模型属性的名称和HTML中字段的名称绑定到模型的属性。在您的代码中:

var TabPrograms = (from l in Model.PrefPrograms
                   where l.SubcategoryName == @AccordionTabName
                   select l);
}                              
@Html.EditorFor(m => TabPrograms)    

HtmlHelper不知道UserViewModel中属性的名称是什么。它采用“TabPrograms”局部变量名称来生成HTML中的字段名称,如:

<input name="TabPrograms[0].EmailStatus" data-val="true" data-val-number="The field EmailStatus must be a number." data-val-required="The EmailStatus field is required." id="TabPrograms_0__EmailStatus"  type="hidden" value="0" />

因此,MVC将尝试将上述字段中的值绑定到UserViewModel中名为“TabPrograms”的属性(它应该是PreferenceProgramModel对象的集合)。你在UserViewModel类中有“TabPrograms”属性吗?如果没有,您应该创建它,这些字段中的数据将绑定到它。另一个更好的解决方案是使用“PrefPrograms”局部变量名而不是“TabPrograms”

答案 1 :(得分:0)

我现在已经解决了这个问题,但最终只需添加几个隐藏字段,并在将数据发布到我的接收操作方法后通过回调我的数据源来重建模型。

我在Preferences.cshtml视图中遇到了另一个问题,因为我试图解析我的集合,以便在界面中的单独分组区域中显示特定的集合项。 @ Html.EditorFor帮助器方法导致自动生成的表单ID互相攻击,因为我从特定循环多次调用集合上的@ Html.EditorFor。我可以通过从Html.EditorFor切换到Html.RenderPartial并使用Steve Sanderson的BeginCollectionItem帮助程序来解决这个问题,如下所述:

http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

如果您有任何疑问或希望了解我是如何完成此任务,请随时与我联系。

非常感谢你的帮助!