【问题标题】:Why doesn't the default model binder update my partial view model on postback?为什么默认模型绑定器不会在回发时更新我的​​部分视图模型?
【发布时间】:2010-11-25 02:43:38
【问题描述】:

我有一个包含另一个类作为其属性之一的类。

public class SiteProperties
{
    public SiteProperties()
    {
        DropFontFamily = "Arial, Helvetica, Sans-serif";
    }
    public string DropFontFamily { get; set; }

    private ResultPageProperties m_ResultPagePropertyList;
    public ResultPageProperties ResultPagePropertyList
    {
        get
        {
            if (m_ResultPagePropertyList == null)
                m_ResultPagePropertyList = new ResultPageProperties();
            return m_ResultPagePropertyList;
        }
        set { m_ResultPagePropertyList = value; }
    }
}

第二类只有一个属性

public class ResultPageProperties
{
    public ResultPageProperties()
    {
        ResultFontFamily = "Arial, Helvetica, Sans-serif";
    }
    public string ResultFontFamily { get; set; }
}

我的控制器只是抓取 SiteProperties 并返回视图。提交时,它接受 SiteProperties 并返回相同的视图。

public class CompanyController : Controller
{
    public ActionResult SiteOptions(int id)
    {
        SiteProperties site = new SiteProperties();
        PopulateProperyDropDownLists();
        return View("SiteOptions", site);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult SiteOptions(SiteProperties properties)
    {
        PopulateProperyDropDownLists();
        return View("SiteOptions", properties);
    }

    private void PopulateProperyDropDownLists()
    {
        var fontFamilyList = new List<SelectListItem>();
        fontFamilyList.Add(new SelectListItem() { Text = "Arial, Helvetica, Sans-serif", Value = "Arial, Helvetica, Sans-serif" });
        fontFamilyList.Add(new SelectListItem() { Text = "Times New Roman, Times, serif", Value = "Times New Roman, Times, serif" });
        fontFamilyList.Add(new SelectListItem() { Text = "Courier New, Courier, Monospace", Value = "Courier New, Courier, Monospace" });
        ViewData["FontFamilyList"] = fontFamilyList;
    }
}

视图包含呈现 ResultPageProperties 模型的局部视图。

<% using (Html.BeginForm("SiteOptions", "Company", FormMethod.Post))
   {%>

    <p><input type="submit" value="Submit" /></p>
    <div>View level input</div>
    <div>
        <label>Font family</label><br />
        <%= Html.DropDownListFor(m => m.DropFontFamily, ViewData["FontFamilyList"] as List<SelectListItem>, new { Class = "UpdatesDropDownExample" })%>
    </div>

    <% Html.RenderPartial("ResultPagePropertyInput", Model.ResultPagePropertyList); %>

<% } %>

部分只是

<div style='margin-top: 1em;'>View level input</div>
<div>
    <label>Font family</label><br />
    <%= Html.DropDownListFor(m => m.ResultFontFamily, ViewData["FontFamilyList"] as List<SelectListItem>, new { Class = "UpdatesResultPageExample" })%>
</div>

好的,所以当页面呈现时,您在两个选择中都会得到“Arial, ...”。如果您为两者选择另一个选项并单击提交,则活页夹会填充 SiteProperties 对象并将其传递给控制器​​。但是,ResultFontFamily 始终包含原始值。我期待它具有用户选择的值。

我错过了什么?

【问题讨论】:

    标签: asp.net-mvc


    【解决方案1】:

    这里的问题是 html 助手的工作方式(所有这些):当尝试绑定时,它们将首先查看 POST 请求值,然后是模型和视图数据以提取值。这是设计使然。这基本上意味着即使在您的后控制器操作中您尝试修改值,html 助手也不会使用它们并选择那些最初由用户发布的值。

    <%= Html.DropDownListFor(m => m.DropFontFamily, 
        ViewData["FontFamilyList"] as List<SelectListItem>, 
        new { Class = "UpdatesDropDownExample" })
    %>
    

    DropDownListFor 助手检测到 ResultFontFamily 有一个发布值,并将使用它而不是您在控制器中提供的值。

    一种可能的解决方法是编写自己的帮助程序。

    【讨论】:

    • 我一定没有把问题说清楚。 html 助手正在做他们应该和期望的事情。他们在模型中显示我传递给他们的内容。问题是关于粘合剂的。当模型的属性是传递给局部视图的类时,绑定器不会填充它。我必须在后控制器操作中包含一个附加参数,以使活页夹使用用户输入填充它。
    【解决方案2】:

    如果你查看调试器并设置断点

    public SiteProperties()
    {
     ***HERE***        DropFontFamily = "Arial, Helvetica, Sans-serif";
    }
    

    然后您可以看到,当您执行回发时,出于某种原因,它会在到达 PopulateProperyDropDownLists() 之前尝试使用默认构造函数;

    http://ubiquitous-tech.blogspot.com/2009/05/aspnet-mvc-post-to-controllers.html

    有几个关于如何处理回发部分的选项

    还有

    public class ResultPageProperties
    {
       public ResultPageProperties()
       {
            ResultFontFamily = "Arial, Helvetica, Sans-serif";
       }
       private string _resultFontFam;
       public string ResultFontFamily {
           get { return _resultFontFam; }
           set { _resultFontFam = value; }
       } 
    }
    

    似乎工作......我无法开始告诉你为什么

    【讨论】:

    • 感谢飓风的帮助。我认为声明 ResultFontFamily 属性的两种方式是等价的。这确实让我想到了我初始化类属性的方式。因为我在我的 getter 中检查 null,所以我总是得到原始值。当我把它拿出来时,我在后控制器方法上留下了一个空值。
    【解决方案3】:

    如果我将我的 ResultPageProperties 属性声明方式更改为

    public ResultPageProperties ResultPagePropertyList { get; set; }
    

    代替

    private ResultPageProperties m_ResultPagePropertyList;    
    public ResultPageProperties ResultPagePropertyList    
    {    
        get    
        {    
            if (m_ResultPagePropertyList == null)    
                m_ResultPagePropertyList = new ResultPageProperties();    
            return m_ResultPagePropertyList;    
        }    
        set { m_ResultPagePropertyList = value; }    
    }  
    

    在 post 方法上为 null。所以活页夹似乎忽略了它。

    所以我将控制器方法更改为以下确实有效的方法。

    [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult SiteOptions(SiteProperties properties, ResultPageProperties resultPageProp)
        {
            properties.ResultPagePropertyList = resultPageProp;
    
            PopulateProperyDropDownLists();
            return View("SiteOptions", properties);
        }
    

    【讨论】:

      【解决方案4】:

      使用 Html.EditorFor 代替 Html.RenderPartial。

      见Model binding with nested child models and PartialViews in ASP.NET MVC。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-15
        • 2011-08-16
        • 1970-01-01
        相关资源
        最近更新 更多