2012-12-18 2 views
2

현재 프로젝트의 편집 기능을 사용하고 있으며 View Model을 가져 와서보기에서 컨트롤러로 다시 전달할 수 없습니다. 보기 모델의 구조는 다음과 같은 수 있습니다 :MVC 3의 HttpPost 메서드에 Complex ViewModel 전달

public class CreateUserViewModel : ICreateUserViewModel 
{ 
    #region Properties 
    public string UserName { get; set; } 
    public string Password { get; set; } 
    public string Email { get; set; } 
    public string SelectedUserType { get; set; } 
    public List<ICreateUserItemViewModel> UserTypes { get; set; } 
    public List<ICreateUserItemViewModel> Products { get; set; } 
    public List<ICreateUserItemViewModel> Languages { get; set; } 
    #endregion 

    #region Constructor 
    public CreateUserViewModel() 
    { 
    } 

    public CreateUserViewModel(List<Product> products, List<Language> languages) 
    { 
     Products = new List<ICreateUserItemViewModel>(); 
     foreach (var prod in products) 
     { 
      var prodVM = new CreateUserItemViewModel 
      { 
       Name = prod.Name, 
       IsSelected = false, 
       ID = (int)prod.ID 
      }; 
      Products.Add(prodVM); 
     } 

     Languages = new List<ICreateUserItemViewModel>(); 
     foreach (var lang in languages) 
     { 
      var langVM = new CreateUserItemViewModel 
      { 
       Name = lang.Name, 
       IsSelected = false, 
       ID = (int)lang.ID 
      }; 
      Languages.Add(langVM); 
     } 

    } 
    #endregion 
} 

서브 클래스 뷰 모델 CreateUserItemViewModel :

public class CreateUserItemViewModel : ICreateUserItemViewModel 
{ 
    public string Name { get; set; } 
    public int ID { get; set; } 
    public bool IsSelected { get; set; } 
} 

내가이 서브 클래스는 체크 박스로도 표현 될 수 있으므로 사용자가 포함하도록 선택할 수 있습니다 싶어 그것 또는 아닙니다.

사용자 컨트롤러 : 나는 사용자 이름 암호와 이메일의 속성이 채워집니다하지만, 제품 및 언어가 비어 응용 프로그램의이 부분에 브레이크 포인트를 넣어

[HttpPost] 
public ActionResult Create(CreateUserViewModel model) 
{ 
    if (ModelState.IsValid) 
    { 
     User newUser = new User(); 
     newUser.UserName = model.UserName; 
     newUser.Password = model.Password; 
     newUser.Email = model.Email; 
     newUser.Products = model.Products; //Always NULL 

. 이다

UserName=asdasdsdasd&Password=asd&Email=asD%40asd.com&type.IsSelected=Admin 
&prod.ID=1&prod.IsSelected=true&prod.IsSelected=false 
&prod.ID=2&prod.IsSelected=false 
&prod.ID=3&prod.IsSelected=false 
&prod.ID=4&prod.IsSelected=false 
&lang.ID=1&lang.IsSelected=true&lang.IsSelected=false 
&lang.ID=2&lang.IsSelected=true&lang.IsSelected=false 
&lang.ID=3&lang.IsSelected=false 
&lang.ID=4&lang.IsSelected=false 
&lang.ID=5&lang.IsSelected=false 
&lang.ID=6&lang.IsSelected=false 
&lang.ID=7&lang.IsSelected=false 
&lang.ID=8&lang.IsSelected=false 
&lang.ID=9&lang.IsSelected=false 
&lang.ID=10&lang.IsSelected=false 
&lang.ID=11&lang.IsSelected=false 
&lang.ID=12&lang.IsSelected=false 
&lang.ID=13&lang.IsSelected=false 
&lang.ID=14&lang.IsSelected=false 
&lang.ID=15&lang.IsSelected=false 
&lang.ID=16&lang.IsSelected=false 
&lang.ID=17&lang.IsSelected=false 
&lang.ID=18&lang.IsSelected=false 
&lang.ID=19&lang.IsSelected=false 

보기 만들기에 대한 코드의 덩어리 : 나는 컨트롤러에 전달되고 있던 것을보고 Fiddler2를 사용하고이 출력되었다 나는이 작업을 한

<div class="editor-label"> 
    @Html.Label("User Products:") 
</div> 
<div class="editor-field"> 
    @foreach (var prod in Model.Products) 
    { 
     @Html.Label(prod.Name) 
     @Html.HiddenFor(x => prod.ID) 
     @Html.CheckBoxFor(x => prod.IsSelected, new { name = prod.Name }) 
    } 
</div> 
<div class="editor-label"> 
    @Html.Label("User Languages:") 
</div> 
<div class="editor-field"> 
    @foreach (var lang in Model.Languages) 
    { 
     @Html.Label(lang.Name) 
     @Html.HiddenFor(x => lang.ID) 
     @Html.CheckBoxFor(x => lang.IsSelected, new { name = lang.Name }) 
    } 
</div> 
<p> 
    <input type="submit" value="Create" /> 
</p> 

꽤 오랫동안 내가하려고하는 것은 가능하지 않다고 생각하기 시작했습니다. 나는 그것이 사용자가 선택한 모든 값으로 완전히 채워진 CreateUserViewModel을 반환하기를 원하지만, 이것을 달성하는 방법을 모르겠습니다.

아이디어가 있으십니까?

답변

6

foreach 대신 for 루프를 사용하십시오.

@for (int i=0; i < Model.Products.Count; i++) 
{ 
    @Html.Label(prod.Name) 
    @Html.HiddenFor(model => model.Products[i].ID) 
    @Html.CheckBoxFor(model => model.Products[i].IsSelected, new { name = prod.Name }) 
} 

귀하의 속성 식 모델에 POST 값을 바인딩하는 방법을 알아 내기 위해 모델 바인더에 대한 충분한 정보를 포함해야합니다.

ICreateUserItemViewModel에 대한 편집기 템플릿을 만든 다음 마크 업을 다음과 같이 변경해보십시오.

@Html.EditorFor(model => model.Products) 
+1

EditorFor 접근법이 마음에 들었습니다. –

+0

정말 효과적입니다. 내가 foreach가 아닌 for 루프가 필요한 이유를 설명해 주시겠습니까? 데이터가 컨트롤러에 어떻게 다시 전달되는지에 대한 근본적인 이해가 부족하다고 생각합니다. – stuartmclark

+0

"for"루프를 사용하면 게시 된 목록을 viewmodel에 바인딩 할 수있는 항목 목록에 색인이 적용됩니다. 예를 들어 게시 된 값은 ... products [0] .ID = 1 & products [0] .IsSelected = true & products [1]입니다.ID = 2 & products [2] .IsSelected = true. 자세한 정보를 위해 게시 한 모델 바인딩 기사의 소개를 확인하십시오. – Sunny

1

으로 이미 게시 대답에 언급, 그것은 인덱스를 적용하여 수행하지만 요소가 비 순차적 경우 또한

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

는 "모델을 도입 한 아래 참조 기사 아래 참조 할 수있다 제안 목록에 추가

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

"바인딩, 제거 고려 ViewModel에서 CreateUserViewModel (제품 나열, 언어 나열). ViewModel은 속성 만 포함하고 컨트롤러 내부에 추가 논리를 배치해야합니다 (예 : 사용자 유형을 사용자의 경우에 연결하는 등).