2016-09-06 3 views
-2

다음 뷰 모델 구조가 있습니다 : BaseViewModel 유형의 속성 모델을 포함하는 ItemViewModel.포스트 ASP.NET MVC에 중첩 된 뷰 모델 바인딩 목록

이 구체적인 예에서 Model은 WeekManagerWorkScheduleViewModel 유형입니다. 이 뷰 모델은 차례로 ManagerWorkScheduleViewModel 유형의 IEnumerable로 구성됩니다. ., 사용되는 다음 ItemView.cshtml 내부

:

<form class="form-horizontal" id="@Model.FormName" name="@Model.FormName" onsubmit="@Model.OnSubmitFunction"> 
    <div class="form-group form-group-sm"> 
     @Html.EditorFor(model => model.Model, Model.ItemViewName + "View") 
    </div> 
    <button class="btn pull-left" type="submit" style="margin: 2px;"> 
     <span class="glyphicon glyphicon-save"></span> 
     @Model.ViewConfiguration.SaveText @Model.ItemTitle 
    </button> 
</form> 

내가 몇 가지 세부 사항을 생략 한 (기본적으로 CRUD 버튼을 추가할지 여부를 결정하는 것 경우의 무리가 Model.ItemViewName는 유형 이름입니다 (의 이 경우 그 WeekManagerWorkScheduleViewModel)

public class WeekManagerWorkScheduleViewModel : BaseViewModel 
{ 
    [HiddenInput] 
    public int RegionId { get; set; } 
    [HiddenInput] 
    public IEnumerable<DateTime> Dates { get; set; } 

    public IEnumerable<ManagerWorkScheduleViewModel> WorkSchedules { get; set; } 
} 

가 WeekManagerWorkScheduleView.cshtml은 다음과 같습니다.

@using DRSTransportPortal.ViewModels 
@model WeekManagerWorkScheduleViewModel 
@{ 
    ViewBag.Title = "Ugentlig arbejdsplan - ledere"; 
} 

@Html.HiddenFor(m => m.RegionId) 

<table class="table"> 
    <thead> 
     <tr> 
      <th><b>Leder</b></th> 
      <th><b>Uge</b></th> 
      <th><b>Mandag</b></th> 
      <th><b>Tirsdag</b></th> 
      <th><b>Onsdag</b></th> 
      <th><b>Torsdag</b></th> 
      <th><b>Fredag</b></th> 
      <th><b>Lørdag</b></th> 
      <th><b>Søndag</b></th> 
     </tr> 
     <tr> 
      <th></th> 
      <th></th> 
       @foreach (var date in Model.Dates) 
       { 
        <th><i><small>@date.Date.ToString("dd-MM-yyyy")</small></i></th> 
       } 
     </tr> 
    </thead> 
    <tbody> 
    @Html.EditorFor(m => m.WorkSchedules) 
    </tbody> 
</table> 
,536,913 63,210

내가보기/imalazysod/EditorTemplates (나는 면도기에서 파생 된 사용자 지정보기 엔진을 사용하고 같은 MVC는이 위치를 알고)에 거주 ManagerWorkScheduleViewModel.cshtml라는 전망이 :

@using DRSTransportPortal.ViewModels 
@model ManagerWorkScheduleViewModel 
<tr id="@Model.Id"> 
    <td>@Html.HiddenFor(m => m.Id)</td> 
    <td>@Html.DisplayFor(m => m.ManagerName, new { htmlAttributes = new { @class = "form-control editoritem" } })</td> 
    <td>@Html.DisplayFor(m => m.DateWeekText, new { htmlAttributes = new { @class = "form-control editoritem" } })</td> 
    <td>@Html.EditorFor(m => m.MondayCodeChoice, new { @class = "form-control editoritem" })</td> 
    <td>@Html.EditorFor(m => m.TuesdayCodeChoice, new { @class = "form-control editoritem" })</td> 
    <td>@Html.EditorFor(m => m.WednesdayCodeChoice, new { @class = "form-control editoritem" })</td> 
    <td>@Html.EditorFor(m => m.ThursdayCodeChoice, new { @class = "form-control editoritem" })</td> 
    <td>@Html.EditorFor(m => m.FridayCodeChoice, new { @class = "form-control editoritem" })</td> 
    <td>@Html.EditorFor(m => m.SaturdayCodeChoice, new { @class = "form-control editoritem" })</td> 
    <td>@Html.EditorFor(m => m.SundayCodeChoice, new { @class = "form-control editoritem" })</td> 
</tr> 

은 "선택"속성을 모두 ChoiceViewModel.cshtml를 사용하여 ChoiceViewModel 유형입니다.

지금, 모든 것이 제대로 렌더링 : Screenshot (names omitted). Red box indicates 1 (one) nested viewmodel

생성 된 HTML은 다음과 같습니다 (첫 번째 행과 처음 몇 세포가 여기에 표시됩니다) :

<tr id="134"> 
    <td><input name="Model.WorkSchedules[0].Id" id="Model_WorkSchedules_0__Id" type="hidden" value="134" data-val-required="Feltet Id skal udfyldes." data-val="true" data-val-number="The field Id must be a number."></td> 
    <td>OMITTED</td> 
    <td>2016 - 36</td> 
    <td> 
    <select name="Model.WorkSchedules[0].MondayCodeChoice.SelectedValue" class="form-control editoritem dropdown" id="SelectChoices" onchange=""> 
     <option value="1">06:00 - 14:00</option> 
     <option value="19">06:00 - 18:00</option> 
     <option value="31">08:00 - 16:00</option> 
     <option value="2">10:00 - 18:00</option> 
     <option value="32">10:00 - 18:00</option> 
     <option value="23">Bagvagt</option> 
     <option value="22">Ferie</option> 
     <option value="8">Fri</option> 
     <option value="3">Kontor</option> 
     <option value="15">Kussus</option> 
     <option value="16">Syg</option> 
    </select> 
    </td> 
REST OF HTML IS OMMITTED (CONTINUES FOR 12 ROWS WITH 10 CELLS EACH) 
</tr> 

을 그러나, 나는 다시 게시 할 때 (jQuery, ajax btw 사용) 이것은 내가 얻은 것입니다. Controller breakpoint, after modelbinding

BaseViewModel에 사용자 지정 모델 바인더를 넣고 보았지만 n 괜찮아 보입니다. 올바른 유형 (WeekManagerWorkScheduleViewModel 등)을 결정합니다. 이것을 사용하면 ControllerContext -> ...-> Request의 Forms 요소가 다음과 같이됩니다. {Model.Id = 141 & ModelType = DRSTransportPortal.ViewModels.WeekManagerWorkScheduleViewModel % 2c + DRSTransportPortal % 2c + Version % 3d1.0.0.0 % 2c + 문화 % 3dneutral % 2C + PublicKeyToken 3dnull % & & Model.RegionId = 1 % Model.WorkSchedules 5b0 5d.Id % = 134 % & Model.WorkSchedules 5b0 5d.MondayCodeChoice.SelectedValue % = 22 %의 & Model.WorkSchedules 5b0 %의 5D .TuesdayCodeChoice.SelectedValue = 1 & Model.WorkSchedules %의 5b0 5d.WednesdayCodeChoice.SelectedValue % = 1 % & Model.WorkSchedules의 5b0 5d.ThursdayCodeChoice.SelectedValue % = 1 % & Model.WorkSchedules의 5b0 % 5d.FridayCodeChoice.SelectedValue = 1 모델 & .WorkSchedules % 5b0 % 5d.Saturday 모든 바인딩이 만들어집니다 : CodeChoice.SelectedValue = 1 & Model.WorkSchedules %의 5b0 % 5d.SundayCodeChoice.SelectedValue = 1 &는 ..... 나는 다음과 같은 사실이 있는지 만들었

ALL (12) NESTED VIEWMODELS} 계속 속성 (기본값. {get; set;}) BaseViewModel을 포함한 viewmodels에는 생성자가 없습니다.기본 생성자를 생성해야 함) 모든 속성 및 클래스는 public입니다.

그래서 ... 제 질문은 왜 모델 바인더가 목록의보기 모델을 만들 수 없습니까? 나는 다른 곳에서 템플릿을 사용하는 데 아무런 문제가 없다. 사람, 즉. 한 번에 하나의 행). 예, MVC 모델 바인딩과 관련된 많은 질문과 많은 답변이 있지만이 카테고리에 속하는 것은 거의 없습니다 (도서의 경우도 마찬가지 임). 실제로 나를 괴롭히는 것은 12 개 항목의 목록이 필요하다고 인식되지만 채워지지 않은 것입니다.

편집 :

public class BaseViewModelBinder : DefaultModelBinder 
{ 
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) 
    { 
     var typeValue = bindingContext.ValueProvider.GetValue("ModelType"); 
     var type = Type.GetType((string) typeValue.ConvertTo(typeof (string)), true); 
     if(!typeof(BaseViewModel).IsAssignableFrom(type)) 
      throw new InvalidOperationException("NOT A BASEVIEWMODEL"); 

     var model = Activator.CreateInstance(type); 
     bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type); 
     return model; 
    } 
} 

[ModelBinder(typeof(BaseViewModelBinder))] 
public class BaseViewModel 
{ 
    [HiddenInput] 
    public int Id { get; set; } 
    [HiddenInput] 
    public DateTime Created { get; set; } 
    [HiddenInput] 
    public DateTime Edited { get; set; } 
    public virtual string SelectionName { get; set; } 
} 

편집 2 :

[HttpPost] 
    public override async Task<JsonResult> Save(ItemViewModel item, string parentName, int? parentId) 
    { 
     if (item?.Model == null) 
     { 
      const int result = 0; 
      return Json(new { result }); 
     } 
     var model = item.Model as WeekManagerWorkScheduleViewModel; 
     if (model == null) 
     { 
      const int result = 0; 
      return Json(new { result }); 
     } 

     foreach (var inner in model.WorkSchedules) 
     { 

     } 
     return await base.Save(item, parentName, parentId); 
    } 

public class ManagerWorkScheduleViewModel : BaseViewModel 
{ 
    [HiddenInput] 
    public int? ManagerId { get; set; } 
    [DisplayName("Leder")] 
    public string ManagerName { get; set; } 

    [HiddenInput] 
    public int? DateWeekId { get; set; } 
    [DisplayName("År/Uge")] 
    public string DateWeekText { get; set; } 

    [HiddenInput] 
    public int? MondayCodeId { get; set; } 

    [UIHint("ChoiceViewModel")] 
    [DisplayName("Mandag")] 
    public ChoiceViewModel MondayCodeChoice { get; set; } 

    [HiddenInput] 
    public int? TuesdayCodeId { get; set; } 

    [UIHint("ChoiceViewModel")] 
    [DisplayName("Tirsdag")] 
    public ChoiceViewModel TuesdayCodeChoice { get; set; } 

    [HiddenInput] 
    public int? WednesdayCodeId { get; set; } 

    [UIHint("ChoiceViewModel")] 
    [DisplayName("Onsdag")] 
    public ChoiceViewModel WednesdayCodeChoice { get; set; } 


    [HiddenInput] 
    public int? ThursdayCodeId { get; set; } 

    [UIHint("ChoiceViewModel")] 
    [DisplayName("Torsdag")] 
    public ChoiceViewModel ThursdayCodeChoice { get; set; } 

    [HiddenInput] 
    public int? FridayCodeId { get; set; } 

    [UIHint("ChoiceViewModel")] 
    [DisplayName("Fredag")] 
    public ChoiceViewModel FridayCodeChoice { get; set; } 

    [HiddenInput] 
    public int? SaturdayCodeId { get; set; } 

    [UIHint("ChoiceViewModel")] 
    [DisplayName("Lørdag")] 
    public ChoiceViewModel SaturdayCodeChoice { get; set; } 

    [HiddenInput] 
    public int? SundayCodeId { get; set; } 

    [UIHint("ChoiceViewModel")] 
    [DisplayName("Søndag")] 
    public ChoiceViewModel SundayCodeChoice { get; set; } 
} 
+0

오, btw, ASP.NET MVC 5를 사용하여 (내 생각 .. 그 중 하나는 전에 코어 :) – SayyesTono

+0

당신은 파생 클래스를 사용할 수 없습니다. 관련 코드 (모델 또는 컨트롤러 메소드는 표시되지 않지만 'Model'속성이 BaseViewModel 유형 인 경우 DefaultModelBinder는'WeekManagerWorkScheduleViewModel' 및'WeekManagerWorkScheduleViewModel' 속성이 아닌'BaseViewModel'을 초기화합니다. 'BaseViewModel'에없는 것들은 무시 될 것입니다. –

+0

ModelBinder 안에 브레이크 포인트를 넣으면 올바른 모델을 사용하고 또한 최상위 모델의 모든 속성 (숨겨진 입력 값)이 올바르게 생성되어 올바른 값이 주어집니다. 또한, BaseViewModel에서 파생 된 모든 viewmodels에 대한 매력처럼 작동합니다. – SayyesTono

답변

0

아, 저 바보. 나는이 프레임 워크를 실제로 어떻게 만들 었는지 잊어 버렸다.

주로 CRUD 작업을 위해 만들었으므로 비어있는 컨트롤러뿐 아니라 각 비즈니스 엔터티에 대한 viewmodel (BaseViewModel에서 파생 됨),보기, 저장소 및 dto 유형을 정의하면됩니다. 그런 다음 다른 모든 것들은 컨트롤러의 표준 세트 (필요한 기능에 따라 세 가지 수준의 파생 수준)를 사용하며 비즈니스 엔티티에 대한 config 항목을 작성하고 VM,보기, repo 유형 및 일부 CRUD를 정의하는 것만 큼 단추 및 레이블 옵션. 최상위 뷰 모델과 뷰는 모두 ItemView, ItemViewModel, ItemListView, SingleSelector, MultipleSelector 등과 같습니다.

내가 잊어 버렸던 것은 한 번에 하나의 비즈니스 엔티티로 제한되어 있었기 때문에 클래스를 출력했습니다 modelbinder를 참조하십시오), 그래서 파생 된 뷰 모델을 사용할 수 있습니다 ...이 경우에는 분명히 예외가 있습니다.

바인딩은 목록을 채우려 고 시도 할 때 첫 번째 viewmodel 유형 (POST 이후에 알려진 유일한 ID)을 사용하여 채우려고 시도하지만 파생되지는 않습니다. 젠장! 그래서 다시 드로잉 테이블 (아무 중첩 :()

+0

기본 라이브러리 modelbinder (질문 중 하나) 대신 사용되는 사용자 정의 모델 바인더의 정적 사전을 추가하여 해결했습니다. 이제는 몇 군데에서 중첩 된 뷰 모델이 필요합니다. 공유 라이브러리를 종속 관계없이 오염시키지 마십시오. :) – SayyesTono