2013-06-18 88 views
29

請耐心等待我的noobness,我是超新的MVC模式。MVC 4 - 在局部視圖中使用不同的模型

我試圖做

我建立給註冊用戶的個人資料信息頁上我的網站。這個頁面將列出關於用戶的數據,例如出生日期,電話號碼,訂閱狀態等等。你明白了。我還想要一個表單讓用戶在同一頁上更改他們的密碼,電子郵件地址,個人信息

我的問題

通過傳遞模型變量用戶的數據來自我的控制器:

public ActionResult Profil() 
     { 
      var model = db.Users.First(e => e.UserName == WebSecurity.CurrentUserName); 
      return View(model); 
     } 

輸出看起來像這樣在我的觀點:

<label>Phone number: </label> 
      @if (Model.PhoneNumber != null) 
        { 
         @Model.PhoneNumber 
        } 
        else 
        { 
         <span class="red">You haven't set up your phone number yet. </span> 
        } 

形式其中用戶可以更改他的信息將使用另一個模型ProfileModel。所以basiccaly我需要在我看來使用兩個模型,一個用於輸出信息,另一個用於發佈數據。我認爲,使用局部視圖,我可以做到這一點,但我得到這個錯誤:

The model item passed into the dictionary is of type 'Applicense.Models.User', but this dictionary requires a model item of type 'Applicense.Models.ProfileModel'.

這裏是我的局部視圖調用如下:

@using (Html.BeginForm()) 
    { 
     @Html.AntiForgeryToken() 
     @Html.ValidationSummary() 

     @Html.Partial("_ModifyProfileInfo") 
    } 

這裏的局部視圖:

@model Applicense.Models.ProfileModel 
<ul> 
    <li> 
     @Html.LabelFor(m => m.Email) 
     @Html.EditorFor(m => m.Email) 
    </li> 
    <li> 
     @Html.LabelFor(m => m.ConfirmEmail) 
     @Html.EditorFor(m => m.ConfirmEmail) 
    </li> 
    <input type="submit" value="Update e-mail" /> 
</ul> 

最後這裏是我的ProfileModel:

public class ProfileModel 
    { 
     [Required] 
     [DataType(DataType.EmailAddress)] 
     [Display(Name = "New e-mail address")] 
     public string Email { get; set; } 

     [DataType(DataType.EmailAddress)] 
     [Display(Name = "Confirm new e-mail address")] 
     [Compare("Email", ErrorMessage = "The e-mail and it's confirmation field do not match.")] 
     public string ConfirmEmail { get; set; } 
    } 

我錯過了什麼嗎?什麼是正確的方法來做到這一點?

編輯: 我重拍我的代碼反映了尼古拉Mitev的答案,但現在我有另一個問題。這裏是我得到的錯誤:

Object reference not set to an instance of an object. (@Model.UserObject.LastName)

這隻發生在我發佈更改的電子郵件地址值時。這是我的視圖模型(ProfileModel.cs):

public class ProfileModel 
    { 
     public User UserObject { get; set; } 

     [Required] 
     [DataType(DataType.EmailAddress)] 
     [Display(Name = "Új e-mail cím")] 
     public string Email { get; set; } 

     [DataType(DataType.EmailAddress)] 
     [Display(Name = "Új e-mail cím megerősítése")] 
     [Compare("Email", ErrorMessage = "A két e-mail cím nem egyezik.")] 
     public string ConfirmEmail { get; set; } 

     [DataType(DataType.EmailAddress)] 
     [Display(Name= "E-mail cím")] 
     public string ReferEmail { get; set; } 
    } 

控制器:

public ActionResult Profil() 
     { 
      var User = db.Users.First(e => e.UserName == WebSecurity.CurrentUserName); 

      var ProfileViewModel = new ProfileModel 
      { 
       UserObject = User 
      }; 

      return View(ProfileViewModel); 
     } 

最後,這裏是我user.cs模型類:

[Table("UserProfile")] 
    public class User 
    { 
     [Key] 
     [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
     public int UserId { get; set; } 
     [Column("UserName")] 
     public string UserName { get; set; } 
     [Column("Email")] 
     [Required] 
     public string Email { get; set; } 
     [Column("FirstName")] 
     public string FirstName { get; set; } 
     [Column("LastName")] 
     public string LastName { get; set; } 
     [Column("PhoneNumber")] 
     public string PhoneNumber { get; set; } 
... You get the idea of the rest... 

我想它的發生,因爲該模型是試圖將每個required列中的數據放入數據庫中。

EDIT2: 我PROFIL行動的httppost方法:

[HttpPost] 
     [Authorize] 
     [ValidateAntiForgeryToken] 
     public ActionResult Profil(ProfileModel model) 
     { 
      if (ModelState.IsValid) 
      { 
//insert into database 
       return Content("everything's good"); 
      } 
      else 
      { 
//outputs form errors 
       return View(model); 
      } 
     } 

回答

35

來處理這種情況是使用並通過視圖模型到您的個人資料控制器的最佳方式,視圖模型是要傳遞給您的視圖多個對象包裝類。

public class ProfileUserViewModel 
{ 
    public ProfileModel ProfileModelObject {get; set;} 
    public UserModel UserModelObject {get; set;} 
} 

你的控制器看起來應該像:

public ActionResult Profil() 
{    
    var profileModel = db.Users.First(e => e.UserName == WebSecurity.CurrentUserName); 
    var userModel = //fetch from db. 

    var pmViewModel = new ProfileUserViewModel 
          { 
           ProfileModelObject = profileModel, 
           UserModelObject = userModel 
          }; 

    return View(pmViewModel); 
} 

最後你的觀點:

@model Applicense.Models.ProfileUserViewModel 

<label>Phone number: </label> 

@if (Model.ProfileModelObject.PhoneNumber != null) 
{ 
    @Model.PhoneNumber 
} 
else 
{ 
    <span class="red">You haven't set up your phone number yet. </span> 
} 
+2

謝謝你,就像一個魅力! :) +1也寫得很好的答案。 – PeterInvincible

+0

現在我得到另一個錯誤:(我編輯的問題,以反映它 – PeterInvincible

+0

@Tharline做你的特定記錄,你試圖獲取在LastName字段中的值? –

13

還有就是@Html.Partial過載,它允許您發送ViewData在你的控制器定義的 - 這是我通常使用的方法部分意見。 在您的控制器中將ViewData["mypartialdata"]定義爲ViewDataDictionary。那麼在你看來

@Html.Partial("_ModifyProfileInfo",ViewData["mypartialdata"]) 
1

在你[HttpPost] PROFIL功能,如果modelstate.isvalid是假的,你回你的編輯視圖,但你需要再次定義你的pmViewModel,其他明智的你的局部視圖將不會顯示一個對象。嘗試使用以下內容並讓我們知道發生了什麼

[HttpPost] 
[Authorize] 
[ValidateAntiForgeryToken] 
public ActionResult Profil(ProfileModel model) 
{ 
    if (ModelState.IsValid) 
    { 
     //insert into database 
     return Content("everything's good"); 
    } 
    else 
    { 
     //outputs form errors 
     var pmViewModel = new ProfileUserViewModel 
     { 
      ProfileModelObject = profileModel, 
      UserModelObject = userModel 
     }; 

     return View(model); 
    } 
} 
+0

謝謝!我實際上必須在返回任何視圖之前放置pmViewModel讓它起作用 – PeterInvincible

+0

你聲明瞭'pmViewModel',它永遠不會被使用,對嗎? – SharpC

0

儘管我知道這個問題早就被問過了,但有些人可能仍然會面臨類似的問題。我用來在頁面上傳遞或使用多個視圖模型的一個簡單解決方案是使用ViewBag來保存第二個對象並在視圖中引用它。見下面的例子。

在您的控制器做到這一點:

Obj2 personalDets = new Obj2(); 
DbContext ctx = new DbContext(); 
var details = ctx.GetPersonalInformation; 

foreach(var item in details) { 
    personalDets.Password = item.Password; 
    personalDets .EmailAddress = item.EmailAddress; 
} 

ViewBag.PersonalInformation = personalDets; 

然後在你看來這些屬性變得唾手可得你