2012-06-05 3 views
0

У меня есть страница MVC3, состоящая из следующих компонентов:Сильно типизированных Модель Не Проводка из частичного вида

ProfileController - Содержит все действия и нагрузки всех взглядов ниже

/Профиль/Индекс - Этот метод действий создает экземпляр UserViewModel, который содержит несколько свойств и вложенных коллекций, включая один, называемый PrefPrograms, который имеет тип «PreferencePrograms», который определяется как:

public class PreferencePrograms : List<PreferenceProgram> 

Метод действия «Index» заполнит коллекцию PrefPrograms и остальную часть UserViewModel и передает эту модель в сильно типизированный «Index.cshtml».

Index.cshtml - "UserViewModel" Это сильно типизированных вид типа Он состоит из нескольких частичных представлений. Один частичный вид на этой странице с именем «Preferences.cshtml» обеспечивает форматированное отображение коллекции PrefPrograms. Соответствующая часть Index.cshtml приведена ниже.

@model ProfilePreferenceCenterProto.Models.UserViewModel 

@{ Html.RenderPartial("Preferences", Model); } 

Preferences.cshtml - Это сильно типизированных частичный вид загружается Index.cshtml используя Html.RenderPartial (выше). В Preferences.cshtml у меня есть метод Begin.AjaxForm() для отправки в действие «PreferenceSubmit», а кнопка ввода ввода находится в нижней части этого частичного представления. В частичном представлении я вызываю помощника @ Html.EditorFor() для загрузки шаблона редактора для каждого элемента «PreferenceProgramModel» в коллекции «PrefPrograms».

Вот моя проблема - все элементы правильно загрузить (в том числе частичного вида и editorfor компонентов), но когда я отправляю форму на Preferences.cshtml к действию «PreferencesSubmit», значение в модели не передается (модель , но значения инициализируются только - значения свойства и коллекции фактически не передаются обратно контроллеру).

Parental View Preferences.cshtml показан ниже.

@model ProfilePreferenceCenterProto.Models.UserViewModel 

<div id="accordian"> 
@using(Ajax.BeginForm("PreferencesSubmit", "Profile", new AjaxOptions{ UpdateTargetId = "accordian" })){ 

    <div id="accordion"> 

    <ul class="tabs"> 

    </ul> 

    <div class="panes"> 
    <div> 
    @{ 
     List<string> AffiliateNames = new List<string>(); 
     foreach(ProfilePreferenceCenterProto.Models.PreferenceProgramModel list in Model.PrefPrograms) 
     { 
      AffiliateNames.Add(list.SubcategoryName); 
     } 

     IEnumerable<string> listNames = AffiliateNames.Distinct(); 
     int counter = 0; 
    } 

    @foreach (string AccordionTabName in listNames) 
    { 
    <h2>@AccordionTabName</h2> 
     <div class="pane" @if (counter == 0){ <text>style="display:block;"</text> } > 
     <table> 
     <tr class="row"> 
      <th class="name">Subscription</th> 
      <th class="icon">Email</th>    
      <th class="icon">SMS</th> 
      <th class="icon">Facebook</th> 
      <th class="icon">Mail</th> 
      <th class="icon">Phone</th> 
     </tr> 

    @{ 
    counter++; 
    var TabPrograms = (from l in Model.PrefPrograms 
         where l.SubcategoryName == @AccordionTabName 
         select l); 
    }        
    @Html.EditorFor(m => TabPrograms)      
     </table> 
     </div> 
    } 
    </div> 

     </div> 
    </div> 
     <div align="center"><input type="submit" value="Save Preferences" /></div> 

}

/Общие/EditorTemplates/PreferenceProgramModel.cshtml - Редактор шаблон для элементов «PreferenceProgramModel», определяется следующим образом:

@model ProfilePreferenceCenterProto.Models.PreferenceProgramModel 

<tr class="row"> 
<td class="name">@Model.ListName</td>     
<td class="icon"> 
@if (Model.EmailEnabled) 
{  
    <a id="@Model.EmailFilterID" href="#" onclick="ImageClick(@Html.IdFor(m => m.EmailStatus));"><img height="25" width="28" src="@Model.Email_Icon_NotSelected" /></a> 
} 
</td> 
<td class="icon"> 
@if (Model.SMSEnabled) 
{ 
    <a id="@Model.SMSFilterID" href="#"><img height="25" width="28" src="@Model.SMS_Icon_NotSelected" /></a> 
} 
</td> 
<td class="icon"> 
@if (Model.FBEnabled) 
{ 
    <a id="@Model.FBFilterID" href="#"><img height="25" width="28" src="@Model.FB_Icon_NotSelected" /></a> 
} 
</td> 
<td class="icon"> 
@if (Model.MailEnabled) 
{ 
    <a id="@Model.MailFilterID" href="#"><img height="25" width="28" src="@Model.Mail_Icon_NotSelected" /></a> 
} 
</td> 
<td class="icon"> 
@if (Model.PhoneEnabled) 
{ 
    <a id="@Model.PhoneFilterID" href="#"><img height="25" width="28" src="@Model.Phone_Icon_NotSelected" /></a> 
} 
</td> 
</tr> 

@Html.HiddenFor(m => m.EmailStatus) 
@Html.HiddenFor(m => m.SMSStatus) 
@Html.HiddenFor(m => m.FBStatus) 
@Html.HiddenFor(m => m.MailStatus) 
@Html.HiddenFor(m => m.PhoneStatus) 

<script type="text/javascript"> 
$(document).ready(function() { 

    function ImageClick(Resource) { 
     alert(Resource.attr("value")); 
     if (Resource.attr("value") != 1) { 
      Resource.val("1"); 
     } 
     else { 
      Resource.val("2"); 
     } 
     alert(Resource.attr("value")); 
    } 

    if ("@Model.EmailEnabled" == "True") { 
     $("#@Model.EmailFilterID").click(function() { 

      ImageClick($("#@Html.IdFor(m => m.EmailStatus)")); 
      return false; 
     }); 
    } 

    if ("@Model.SMSEnabled" == "True") { 
     $("#@Model.SMSFilterID").click(function() { 
      ImageClick($("#@Html.IdFor(m => m.SMSStatus)")); 
      return false; 
     }); 
    } 

    if ("@Model.FBEnabled" == "True") { 
     $("#@Model.FBFilterID").click(function() { 
      ImageClick($("#@Html.IdFor(m => m.FBStatus)")); 
      return false; 
     }); 
    } 

    if ("@Model.MailEnabled" == "True") { 
     $("#@Model.MailFilterID").click(function() { 
      ImageClick($("#@Html.IdFor(m => m.MailStatus)")); 
      return false; 
     }); 
    } 

    if ("@Model.PhoneEnabled" == "True") { 
     $("#@Model.PhoneFilterID").click(function() { 
      ImageClick($("#@Html.IdFor(m => m.PhoneStatus)")); 
      return false; 
     }); 
    } 

}); 
</script> 

Действие контроллера PreferencesSubmit определяются с этой подписью:

public ActionResult PreferencesSubmit(Models.UserViewModel model) 

Визуализированная формой тег от страницы находится ниже:

<form action="/Profile/PreferencesSubmit" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#accordian" id="form0" method="post"> 

Некоторые из оказанных скрытых полей приведены ниже:

<input data-val="true" data-val-number="The field EmailStatus must be a number." data-val-required="The EmailStatus field is required." id="TabPrograms_0__EmailStatus" name="TabPrograms[0].EmailStatus" type="hidden" value="0" /> 
<input data-val="true" data-val-number="The field SMSStatus must be a number." data-val-required="The SMSStatus field is required." id="TabPrograms_0__SMSStatus" name="TabPrograms[0].SMSStatus" type="hidden" value="0" /> 
<input data-val="true" data-val-number="The field FBStatus must be a number." data-val-required="The FBStatus field is required." id="TabPrograms_0__FBStatus" name="TabPrograms[0].FBStatus" type="hidden" value="0" /> 
<input data-val="true" data-val-number="The field MailStatus must be a number." data-val-required="The MailStatus field is required." id="TabPrograms_0__MailStatus" name="TabPrograms[0].MailStatus" type="hidden" value="0" /> 
<input data-val="true" data-val-number="The field PhoneStatus must be a number." data-val-required="The PhoneStatus field is required." id="TabPrograms_0__PhoneStatus" name="TabPrograms[0].PhoneStatus" type="hidden" value="0" /> 

Я проверял, что ModelState.IsValid является истинным, когда вызывается PreferencesSubmit, но сама модель не содержит фактических значений со страницы. Как передать мои сильно типизированные значения модели из частичного представления обратно в метод действия для отправки?

ответ

1

Значения, отправленные из формы, привязаны к свойствам модели, основанной на именах свойств модели и названий полей в HTML. В коде:

var TabPrograms = (from l in Model.PrefPrograms 
        where l.SubcategoryName == @AccordionTabName 
        select l); 
}        
@Html.EditorFor(m => TabPrograms)  

HtmlHelper не знает, что имена свойств в UserViewModel. Он принимает «TabPrograms» локальное имя переменной для того, чтобы генерировать имена полей в HTML, как:

<input name="TabPrograms[0].EmailStatus" data-val="true" data-val-number="The field EmailStatus must be a number." data-val-required="The EmailStatus field is required." id="TabPrograms_0__EmailStatus" type="hidden" value="0" /> 

Так MVC будет пытаться связать значение поля выше свойству с именем «TabPrograms» в UserViewModel (и это должен быть набор объектов PreferenceProgramModel). У вас есть свойство «TabPrograms» в классе UserViewModel? Если нет, вы должны создать его, и данные из этих полей будут привязаны к нему. Другим, лучшим решением было бы использовать имя локальной переменной «PrefPrograms» вместо «TabPrograms»

+0

Этот подход определенно помог - я изменил «var TabPrograms» на теперь «var PrefPrograms», и теперь коллекция распознается в методе приема. При этом полная модель не заполнена, присутствует только часть модели, содержащаяся в форме. Есть ли способ получить полную модель для отправки? – Mike

+0

@Mike: на сервер отправляются только поля, содержащиеся в HTML-форме. Вы можете добавить скрытые поля в свою форму с помощью Html.HiddenFor (m => m.FieldName), помните, что для коллекций вы должны перебирать все элементы и использовать для каждого свойства Html.HiddenFor (m => m.CollectionField [i] .Property1). – PanJanek

+0

О, и в MVC нет такой вещи, как «postback». Если вам нужно, вы можете имитировать ее, добавив скрытые поля в вашу форму, но общая идея отличается от MVC, чем в WebForms. – PanJanek

0

Теперь я решил это, но в конечном итоге пришлось просто добавить несколько скрытых полей и перестроить модель, перейдя к моим данным источник после отправки данных в мой метод приема.

Я столкнулся с другой проблемой в своем представлении Preferences.cshtml, так как я пытался разобрать свою коллекцию, чтобы отображать конкретные элементы коллекции в отдельно сгруппированных областях интерфейса. Метод @ Html.EditorFor helper заставил автогенерированные идентификаторы формы топать друг на друга, так как я вызывал @ Html.EditorFor в коллекции несколько раз из определенного цикла. Я был в состоянии работать вокруг этого путем перехода от Html.EditorFor к Html.RenderPartial и с помощью помощника BeginCollectionItem Стива Сандерсон, описанный здесь:

http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

Не стесняйтесь связаться со мной напрямую, если у вас есть какие-либо вопросы или хотели бы чтобы понять, как я это сделал.

Большое вам спасибо за помощь!