Обратная передача в частично загруженном виде возвращает нулевую модель

В моем приложении есть страница с несколькими полями поиска. Когда пользователь нажимает на соответствующую кнопку поиска, ожидается загрузка таблицы результатов. Эта сетка имеет несколько редактируемых элементов управления, в которых пользователь может вносить изменения и нажимать кнопку "Сохранить", если необходимо сохранить данные.

Мы реализовали функциональность, используя AjaxForm и частичное представление.

  1. Область поиска, содержащая поля поиска и кнопку поиска, создается с использованием Ajax.BeginForm, при отправке которого из контроллера вызывается метод обратной передачи. SearchModel передается этому методу.
  2. Частичное представление создано для отображения результатов, и форма Ajax на шаге 1 успешно загружает его из метода обратной передачи контроллера. Свойство SearchModel.Results передается для просмотра в качестве модели.
  3. Это частичное представление, показывающее результаты, имеет кнопку Сохранить (снова форму Ajax), которая вызывает другой метод в контроллере, но получает нулевую модель в контроллере.

перепробовал много трюков, но безуспешно. Какой-нибудь рабочий пример демонстрировался где-нибудь или предложение, чтобы это работало? В Интернете есть много примеров, где объясняется использование AjaxForm для загрузки данных, но не найдено ни одного для нескольких (или вложенных?)

Заранее спасибо.

Изменить - 24 февраля

Вот пример, который я создал с использованием шаблона MVC по умолчанию для Visual Studio, который аналогичен фактическим критериям, описанным выше, и имеет ту же проблему на странице Submit of Partial.

Просмотры:

Index.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. Когда вы редактируете результаты поиска и нажимаете "Отправить" в форме результатов, пожалуйста, установите точку останова, вы увидите, что возвращаемая модель имеет нулевое значение.

Надеюсь, это объяснит мою проблему.

1 ответ

Решение

Теперь, когда вы показали свой реальный код с полным примером, на ваш вопрос можно ответить.

Причина, по которой вы получаете null это потому, что вы не соблюдаете стандартное соглашение об именах для ваших полей ввода, которое ожидает связыватель модели по умолчанию. Пожалуйста, прочитайте 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 Посмотреть
  • Я добавил скрытое поле для свойства Name внутри пользовательского шаблона редактора (@Html.HiddenFor(m => m.Name)), чтобы отправить это значение на сервер при отправке формы, потому что у вас есть только TextArea для поля Address, означающее, что имя никогда не было бы отправлено на ваш сервер.
Другие вопросы по тегам