Есть главная модель которая содержит список моделей которые в свою очередь содержут список моделей....когда вывожу во вью все нормуль все работает....вношу изменения в текстовые поля пытаюсь отправить модель с изменениями но она возвращает пустой список моделей....в чем дело???
В представлении использую MainModel
public class MainModel()
{
public List<Model1>{get;set;}
}
public class Model1()
{
public List<Model2>{get;set;}
public properti1{get;set;}
...
public propertiX{get;set;}
}
public class Model2()
{
public properti1{get;set;}
...
public propertiX{get;set;}
}
Речь об MVC я так понимаю?
Неплохо было бы, конечно, на код View взглянуть для ясности.
Ну скорей всего дело в том, что MVC понятия не имет, как заполнять твой список Model из данных реквеста.
Нужно написать свой ModelBinder.
Пример тут
Здравствуйте, RushDevion, Вы писали:
RD>Речь об MVC я так понимаю?
RD>Неплохо было бы, конечно, на код View взглянуть для ясности.
RD>Ну скорей всего дело в том, что MVC понятия не имет, как заполнять твой список Model из данных реквеста.
RD>Нужно написать свой ModelBinder.
RD>Пример тут
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<russian_promo.Models.MainModel>" %>
<%@ Import Namespace="russian_promo.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Sape
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm())
{ %>
<h2>Sape-задачи</h2>
<!--Таб меню-->
<table>
<tr>
<td> <%: Html.ActionLink("Добавить задачу", "SapeAdd", "Sape")%></td>
<td> <%: Html.ActionLink("Сохранить изменения", "SapeChangesSave", new { model=(MainModel)ViewData.Model })%></td>
<td> <%: Html.ActionLink("Оценка качества", "SapeManagerMurks", "Sape")%></td>
</tr>
</table>
<!--Таб меню-->
<br />
<input id="Submit1" type="submit" value="Сохранить" />
<br />
<%:Html.TextBoxFor(model=>model.str) %>
<%:Html.HiddenFor(model=>model.ListProject) %>
<table class="myTable">
<%for (int i = 0; i < ViewData.Model.ListProject.Count; i++)
{%>
<%Guid projectId = ViewData.Model.ListProject.ElementAt(i).ProjectId; %>
<%:Html.HiddenFor(model=>model.ListProject.ElementAt(i).ProjectId) %>
<tr>
<td >
<%:Html.DisplayTextFor(model => model.ListProject.ElementAt(i).ProjectName)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ProjectName)%>
</td>
<td >
<%:Html.ActionLink(ViewData.Model.ListProject.ElementAt(i).SAPEManager, "SapeManager", new { projectId = ViewData.Model.ListProject.ElementAt(i).ProjectId })%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).SAPEManager)%>
</td>
<td >
<%=Html.Encode(ViewData.Model.ListProject.ElementAt(i).SEO)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).SEO)%>
</td>
<td class="MyTablePadding">
<table class="myTable1">
<%List<SapeTasks> SapeTaskForProject = (List<SapeTasks>)ViewData.Model.ListProject.ElementAt(i).ListProjectSape; %>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape)%>
<%for (int j = 0; j < SapeTaskForProject.Count; j++)
{%>
<tr>
<td>
<%=Html.Encode(SapeTaskForProject.ElementAt(j).DateFirstDay)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).DateFirstDay)%>
</td>
<td>
<%:Html.ActionLink(SapeTaskForProject.ElementAt(j).TaskFile.ToString(), "SapeTask", new { SAPEtaskId = SapeTaskForProject.ElementAt(i).Id })%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).TaskFile)%>
</td>
<td>
<%=Html.Encode(SapeTaskForProject.ElementAt(j).CountLinks)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).CountLinks)%>
</td>
<td>
всего
</td>
<td>
<%:Html.TextBoxFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).LinkAddToday)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).LinkAddToday)%>
</td>
<td>
<%:Html.TextBoxFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).LinkDeleteToday)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).LinkDeleteToday)%>
</td>
<td>
<%string Dateflag = SapeTaskForProject.ElementAt(j).DateStartBay.ToString();
string Datestatus = "";
switch (Dateflag)
{
case "01.01.0001 0:00:00":
Datestatus = "//-----//";
break;
default:
Datestatus = SapeTaskForProject.ElementAt(j).DateStartBay.ToString();
break;
}
%>
<%=Html.Encode(Datestatus)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).DateStartBay)%>
</td>
<td>
<%string Dateflag1 = SapeTaskForProject.ElementAt(j).DateEndBay.ToString();
string Datestatus1 = "";
switch (Dateflag1)
{
case "01.01.0001 0:00:00":
Datestatus1 = "//-----//";
break;
default:
Datestatus1 = SapeTaskForProject.ElementAt(j).DateEndBay.ToString();
break;
}
%>
<%=Html.Encode(Datestatus1)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).DateEndBay)%>
</td>
<td>
<%string Dateflag2 = SapeTaskForProject.ElementAt(j).DateLastDay.ToString();
string Datestatus2 = "";
switch (Dateflag2)
{
case "01.01.0001 0:00:00":
Datestatus2 = "//-----//";
break;
default:
Datestatus2 = SapeTaskForProject.ElementAt(j).DateLastDay.ToString();
break;
}
%>
<%=Html.Encode(Datestatus2)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).DateLastDay)%>
</td>
<td>
<%int flag = SapeTaskForProject.ElementAt(j).status;
string status = "";
switch (flag)
{
case 0:
status = "Новая";
break;
case 1:
status = "В работе";
break;
case 2:
status = "На проверке";
break;
case 3:
status = "Завершено";
break;
}
%>
<%=Html.Encode(status)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ListProjectSape.ElementAt(j).status)%>
</td>
</tr>
<% } %>
</table>
</td>
</tr>
<% } %>
</table>
<%} %>
</asp:Content>
Насколько мне удалось понять визуально это выглядит как таблица проектов для каждого из которых показывается список тасков.
Так, а какое поведение ожидается при нажатии кнопки "Сохранить"? Что все измененные названия проектов (о тасках пока не говорю) сохранятся
и в экшен придет правильно заполненный список проектов. Так не будет. Это слишком сложный биндинг для MVC. Придется писать свой ModelBinder.
Вообще во View много непонятного (а местами страшного
):
<%:Html.HiddenFor(model=>model.ListProject) %>
Что должно быть записано в hidden-поле? Список? Неа. MVC так не может.
<%for (int i = 0; i < ViewData.Model.ListProject.Count; i++) {%> и последующий ListProject.ElementAt(i)
Здесь лучше foreach использовать.
<%:Html.DisplayTextFor(model => model.ListProject.ElementAt(i).ProjectName)%>
<%:Html.HiddenFor(model => model.ListProject.ElementAt(i).ProjectName)%>
Зачем дублировать ProjectName hidden-полем? Да еще с тем же именем.
switch (Dateflag)
{
case "01.01.0001 0:00:00":
Datestatus = "//-----//";
break;
}
Не надо делать такие вещи во въю, иначе придется их дублировать во всех View, где потребуется аналогичная функциональность.
Сделай это либо хелпером, либо свойством ViewModel'и
Ну про хранение строки лучше хранить в ресурсах я уже молчу.
Вообще мне непонятно желание (если я конечно правильно все понял) сохранять все проекты сразу. Сделай список проектов. Сделай отдельное редактирование проекта и будет вам счастье.
На эти казусы не обращайте внимания это я уже от безысходности что только не пробовал)))))))))).....вообще по нажатию на сохранить должно произойти следующее......мы в таски вносим какие либо изменения не обязательно во все....выборочно куда понадобиться и потом сохраняем изменения.....я хотел после отправки в контроллере пробежаться циклом по модели отследить изменения и сохранить но список моделей возвращается пустой
Я нашел пример реализации только у меня возникли вопросы
1.//i don't know how to bind to the list property
fund.FundItems[0].Catalogue.Id = controllerContext.HttpContext.Request.Form["FundItem.Catalogue.Id"];
как именно для списка все это сделать
2.и что мне потом с этим биндером делать когда я его напишу
public class FundModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
throw new NotImplementedException();
}
public object GetValue(ControllerContext controllerContext, string modelName, Type modelType, ModelStateDictionary modelState)
{
var fund = new Fund();
fund.Id = int.Parse(controllerContext.HttpContext.Request.Form["Id"]);
fund.Name = controllerContext.HttpContext.Request.Form["Name"];
//i don't know how to bind to the list property
fund.FundItems[0].Catalogue.Id = controllerContext.HttpContext.Request.Form["FundItem.Catalogue.Id"];
return fund;
}
}
1) Для начала следует понять, зачем вообще нужен биндер.
Когда пользователь сабмитит форму, браузер формирует POST запрос.
Этот запрос можно посмотреть например через
Fidler или
Firebug (Firefox). Рекомендую поставить — очень полезный тул для разработки ModelBinder'ов и не толька
Так вот, если посмотреть, что же там браузер шлет, то можно увидеть строку из имен/значений полей.
Т.е. если во View это было HiddenFor(model=>model.Id), TextBoxFor(model=>model.Description), то в POST это будет id=1&Description=ТекстПользователя&.
И стандартный биндинг MVC легко справляется с такими простыми вещами.
А вот для списков не все сложнее. Почитайте
вот тут пример.
Там же, кстати, написано, как обойтись без биндера (сам я это не проверял). Основная идея в том, что поля должны отличаться по именам, т.е.
в POST это должно быть что-то вроде id1=1&Description1=ТекстПользователя&id2=1&Description2=ТекстПользователя& и т.д. Тогда значения
легко достанутся в биндере.
Просто на то чтобы написать полноценный пример биндера у меня сейчас нет времени.
2) Сами биндеры регистрируются в файле global.asax (метод Application_Start )
ModelBinders.Binders[typeof( FundModelBinder )] = new FundModelBinder();