【问题标题】:Postback on partially loaded view brings null model部分加载视图的回发带来空模型
【发布时间】:2013-02-24 21:46:29
【问题描述】:

我的应用程序的页面很少有搜索框。当用户单击相应的搜索按钮时,预计会加载结果网格。该网格几乎没有可编辑的控件,用户可以在其中修改并在需要时点击保存按钮来保存数据。

我们已经使用 AjaxForm 和局部视图实现了该功能。

  1. 包含搜索框和搜索按钮的搜索区域是使用 Ajax.BeginForm 创建的,在提交时从控制器调用回发搜索方法。 SearchModel 被传递给此方法。
  2. 创建部分视图以显示结果,并且在步骤 1 中的 Ajax 表单从控制器回发方法成功加载它。 SearchModel.Results 属性作为其模型传递给视图。
  3. 这个显示结果的局部视图有一个保存按钮(同样是一个 Ajax 表单),它调用控制器中的另一个方法,但在控制器中获取模型 null。

尝试了很多技巧,但都不成功。任何工作示例在任何地方展示或建议使其工作?网上有很多例子解释了使用 AjaxForm 加载数据,但没有找到任何用于多个(或嵌套?)的示例

提前致谢。

编辑 - 2 月 24 日

这是我使用 Visual Studio 默认 MVC 模板创建的示例,它与上面解释的实际条件类似,并且在提交部分页面时存在相同的问题..

观看次数:

索引.cshtml

    @using MvcApplication1.Models
    @model SearchModel

    @{
        ViewBag.Title = "Home Page";
    }

     <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" ></script>
    <h2>@ViewBag.Message</h2>
    <p>
        To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
    </p>



@Ajax.BeginForm("Search", "Home", new AjaxOptions { HttpMethod = "Post", 
InsertionMode = InsertionMode.Replace,UpdateTargetId = "SearchResults"})
{
     <table>
    <tr>
        <td>
            First Name:
        </td>
        <td>
            @Html.TextBoxFor(m => m.SearchString)
        </td>
    </tr>
    <tr>
        <td colspan="2">
            <input type="submit" value="Submit" />
        </td>
    </tr>
</table>

}
<div id="SearchResults" style="color: Green;"></div>

部分视图 - _SearchResult.cshtml

    @using MvcApplication1.Models
    @model MvcApplication1.Models.SearchModel
    @{
        ViewBag.Title = "Result Partial";
    }
    <h2>
        testPartial</h2>
    @Ajax.BeginForm("SearchResult", "Home", new AjaxOptions
    {
        HttpMethod = "Post"
    })
    {
    <table>
        @foreach (ResultModel item in Model.Result)
        {
            <tr>
                <td>
                    Name:
                </td>
                <td>
                    @Html.DisplayFor(m => item.Name)
                </td>
            </tr>
            <tr>
                <td>
                    Address:
                </td>
                <td>
                    @Html.TextAreaFor(m => item.Address)
                </td>
            </tr>

        }
        <tr>
            <td colspan="2">
                <input type="submit" value="Submit" />
            </td>
        </tr>
    </table>
    }

型号:

SearchModel.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;

    namespace MvcApplication1.Models
    {
        public class SearchModel
        {
            public string SearchString  { get; set; }

            public List<ResultModel> Result { get; set; }
        }
    }

ResultModel.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;

    namespace MvcApplication1.Models
    {
        public class ResultModel
        {
            public string Name { get; set; }
            public string Address { get; set; }
        }
    }

控制器:

HomeController.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using MvcApplication1.Models;

    namespace MvcApplication1.Controllers
    {
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                ViewBag.Message = "Welcome to ASP.NET MVC!";

                return View();
            }

            public ActionResult About()
            {
                return View();
            }

            [HttpPost]
            public ActionResult Search(SearchModel model)
            {
                //dummy search for result
                List<ResultModel> result = new List<ResultModel>();

                ResultModel res1 = new ResultModel();
                res1.Name = model.SearchString + " 1";
                res1.Address = "Dummy address";

                result.Add(res1);

                ResultModel res2 = new ResultModel();
                res2.Name = model.SearchString + " 2";
                res2.Address = "Rummy address";

                result.Add(res2);

                //assign seach results to model
                model.Result = result;

                return PartialView("_SearchResult", model);
            }

            [HttpPost]
            public ActionResult SearchResult(SearchModel model)
            {
                //do something with results

                List<ResultModel> res = model.Result; // null here !!

                return RedirectToAction("Index");
            }
        }
    }

所以,上面的示例将

  1. 在主页上显示一个搜索框 - Index.cshtml
  2. 当您点击提交时,它会在搜索下方加载显示结果的部分视图
  3. 当您编辑搜索结果并在结果表单上点击提交时,请在此处设置断点,您将看到返回的模型为空。

希望,这能解释我的问题。

【问题讨论】:

  • 如果不显示您的代码,恐怕很难说出它可能出了什么问题。
  • 明白,让我创建一个类似的虚拟示例,我会在几个小时内发布它..
  • 达林 - 请参阅上面添加的代码示例。

标签: asp.net-mvc jquery unobtrusive-ajax


【解决方案1】:

现在您已经通过完整的示例展示了您的实际代码,您的问题可以得到回答。

您收到null 的原因是您没有遵守默认模型绑定器所期望的输入字段的标准命名约定。请阅读 Phil Haack 的 following article 以熟悉这些约定。

您的代码的问题在于您在部分代码中使用了foreach 循环来呈现结果,而不是使用编辑器模板。因此,将 _SearchResult.cshtml 中的代码替换为以下内容:

@using MvcApplication1.Models
@model SearchModel
@{
    ViewBag.Title = "Result Partial";
}
<h2>testPartial</h2>

@using(Ajax.BeginForm("SearchResult", "Home", new AjaxOptions()))
{
    <table>
        @Html.EditorFor(x => x.Result)
        <tr>
            <td colspan="2">
                <input type="submit" value="Submit" />
            </td>
        </tr>
    </table>
}

然后为ResultModel 类型定义自定义编辑器模板(~/Views/Shared/EditorTemplates/ResultModel.cshtml - 警告,编辑器模板的名称和位置很重要,因为它按约定工作):

@using MvcApplication1.Models
@model ResultModel

<tr>
    <td>
        Name:
    </td>
    <td>
        @Html.DisplayFor(m => m.Name)
        @Html.HiddenFor(m => m.Name)
    </td>
</tr>
<tr>
    <td>
        Address:
    </td>
    <td>
        @Html.TextAreaFor(m => m.Address)
    </td>
</tr>

注意事项:

  • 我已将Ajax.BeginForm 助手包装在using 语句中。你应该在 Index.cshtml 视图中做同样的事情
  • 我在自定义编辑器模板 (@Html.HiddenFor(m =&gt; m.Name)) 中为 Name 属性添加了一个隐藏字段,以便在提交表单时将此值发送到服务器,因为您的 Address 字段只有一个 TextArea,这意味着名称永远不会发送到您的服务器。

【讨论】:

  • 非常感谢达林,它解决了我的问题。我喜欢他们回答的方式,将确保遵循您建议的标准。也感谢这些提示。除此之外,我想问一下,当数据有很多列和行以及大量的 CSS 用于美化时,这是否是显示数据的正确方法,还是我们应该考虑同样的网格?
  • 看不出这种方法有什么问题。就我个人而言,我不是内置 WebGrid 助手的忠实粉丝,但它可以为您节省一些打字时间。您可以尝试用 WebGrid 替换您的代码,看看它是否适用于您的场景。
  • 好吧,我只是担心性能问题,创建所有低级 HTML 并使用您的视图呈现它会减慢您的页面速度吗? (我很想念我的 ascx 用户控件。)
猜你喜欢
  • 2017-01-24
  • 2016-11-26
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多