2011-12-24 15 views
2

エディタテンプレートを使用して、ユーザーを割り当てることができる各ロールのチェックボックスを表示しています。モデルは次のとおりエディタテンプレートのチェックボックスは、ポストアクションでモデルにバインドされていません

public class UserModel 
{ 
    [Required] 
    [Display(Name = "User name")] 
    public string UserName { get; set; } 

    [Required] 
    [DataType(DataType.EmailAddress)] 
    [Display(Name = "Email address")] 
    public string Email { get; set; } 

    [Required] 
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] 
    [DataType(DataType.Password)] 
    [Display(Name = "Password")] 
    public string Password { get; set; } 

    [DataType(DataType.Password)] 
    [Display(Name = "Confirm password")] 
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 
    public string ConfirmPassword { get; set; } 

    public IEnumerable<string> UserRoles { get; set; } 
} 
public class UserRoleModel 
{ 
    public IEnumerable<RoleViewModel> AllRoles { get; set; } 
    public UserModel user { get; set; } 

    public UserRoleModel() 
    { 
     this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
     { 
      Name = r 
     }); 
     this.user = new UserModel(); 
    } 
} 
public class RoleViewModel 
{ 
    public string Name { get; set; } 
    public bool Selected { get; set; } 
} 

コントローラー:

public ActionResult Create() 
    { 
     return View(new UserRoleModel()); 
    } 

    [HttpPost] 
    public ActionResult Create(UserRoleModel model) 
    { 
     if (ModelState.IsValid) 
     { 
      MembershipCreateStatus createStatus; 
      Membership.CreateUser(model.user.UserName, model.user.Password, model.user.Email, null, null, true, null, out createStatus); 

      if (createStatus == MembershipCreateStatus.Success) 
      { 


       foreach (var r in model.AllRoles) 
       { 
        if (r.Selected) 
        { 
         Roles.AddUserToRole(model.user.UserName, r.Name); 
        } 
       } 

       return RedirectToAction("Index", "Home"); 
      } 
      else 
      { 
       ModelState.AddModelError("", ErrorCodeToString(createStatus)); 
      } 
     } 

     return View(model); 
    } 

ビュー:

@model BBmvc.Areas.Tools.Models.UserRoleModel 


@using (Html.BeginForm()) { 
@Html.ValidationSummary(true) 
<fieldset> 
    <legend>UserModel</legend> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.user.UserName) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.user.UserName) 
     @Html.ValidationMessageFor(model => model.user.UserName) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.user.Email) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.user.Email) 
     @Html.ValidationMessageFor(model => model.user.Email) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.user.Password) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.user.Password) 
     @Html.ValidationMessageFor(model => model.user.Password) 
    </div> 

    <div class="editor-label"> 
     @Html.LabelFor(model => model.user.ConfirmPassword) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.user.ConfirmPassword) 
     @Html.ValidationMessageFor(model => model.user.ConfirmPassword) 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(x => x.AllRoles) 
    </div> 


    <p> 
     <input type="submit" value="Create" /> 
    </p> 
</fieldset> 

}

、エディタテンプレート

@model BBmvc.Areas.Tools.Models.RoleViewModel 
@Html.CheckBoxFor(x => x.Selected) 
@Html.LabelFor(x => x.Selected, Model.Name) 
@Html.HiddenFor(x => x.Name) 
<br /> 

問題は、チェックボックスがオンになっているかどうかにかかわらず、ポストアクションに違いがないことです。何とかモデルに縛られていないようです。

答えて

1

問題は、LINQクエリの遅延実行が原因です。

public class UserRoleModel 
{ 
    public IEnumerable<RoleViewModel> AllRoles { get; set; } 
    public UserModel user { get; set; } 

    public UserRoleModel() 
    { 
     this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
     { 
      Name = r 
     }).ToList(); 
     this.user = new UserModel(); 
    } 
} 

お知らせ.ToList()コール:

this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
{ 
    Name = r 
}).ToList(); 

そして、ここでは説明だあなたは熱心にコレクションを初期化する必要があります。あなたが書くとき:

this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
{ 
    Name = r 
}); 

この時点では、クエリは実行されません。式ツリーだけが構築されますが、実際のクエリは、何かがコレクションの繰り返しを開始するときにのみ実行されます。何が繰り返されますか?最初はそれが見えます。ビュー内には、このコレクションのためのエディタのテンプレートを使用します。AllRoles以来

@Html.EditorFor(x => x.AllRoles) 

は、ASP.NET MVCは自動的に反復処理し、コレクションの各要素のエディタのテンプレートをレンダリングしますコレクションプロパティです。これにより、ビューが適切にレンダリングされます。

ここで、フォームがPOSTされたときにどうなるかを見てみましょう。 Createアクションにポストし、既定のモデルバインダーが呼び出されます。コンストラクターが呼び出されますが、今度はAllRolesプロパティを反復処理するものがないため、クエリは実行されません。実際にはアクションの後半で実行され、値は失われます。

この理由から、コンストラクタ内でビューモデルを初期化しないことをお勧めします。それぞれのコントローラのアクション内でこれを行う方が良いでしょう。そして、

public class UserRoleModel 
{ 
    public IEnumerable<RoleViewModel> AllRoles { get; set; } 
    public UserModel user { get; set; } 
} 

と:

public ActionResult Create() 
{ 
    var model = new UserRoleModel 
    { 
     AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel 
     { 
      Name = r 
     }).ToList(), 
     user = new UserModel() 
    }; 
    return View(model); 
} 
+0

素晴らしいです!ありがとう! – Rob

関連する問題