Речь об MVC я так понимаю?
Неплохо было бы, конечно, на код View взглянуть для ясности.
Ну скорей всего дело в том, что MVC понятия не имет, как заполнять твой список Model из данных реквеста.
Нужно написать свой ModelBinder.
Пример тут
Насколько мне удалось понять визуально это выглядит как таблица проектов для каждого из которых показывается список тасков.
Так, а какое поведение ожидается при нажатии кнопки "Сохранить"? Что все измененные названия проектов (о тасках пока не говорю) сохранятся
и в экшен придет правильно заполненный список проектов. Так не будет. Это слишком сложный биндинг для 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) Для начала следует понять, зачем вообще нужен биндер.
Когда пользователь сабмитит форму, браузер формирует 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();
Есть главная модель которая содержит список моделей которые в свою очередь содержут список моделей....когда вывожу во вью все нормуль все работает....вношу изменения в текстовые поля пытаюсь отправить модель с изменениями но она возвращает пустой список моделей....в чем дело???
В представлении использую 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;}
}
Здравствуйте, 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>
На эти казусы не обращайте внимания это я уже от безысходности что только не пробовал)))))))))).....вообще по нажатию на сохранить должно произойти следующее......мы в таски вносим какие либо изменения не обязательно во все....выборочно куда понадобиться и потом сохраняем изменения.....я хотел после отправки в контроллере пробежаться циклом по модели отследить изменения и сохранить но список моделей возвращается пустой
Я нашел пример реализации только у меня возникли вопросы
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;
}
}