2013-06-18 17 views
29

Si prega di sopportare il mio noobness, sono super nuovo al pattern MVC.MVC 4 - Utilizzare un modello diverso in vista parziale

Quello che sto cercando di fare

Sto costruendo una pagina informazioni del profilo per gli utenti registrati sul mio sito. Questa pagina dovrebbe elencare i dati sull'utente, come la data di nascita, il numero di telefono, lo stato dell'abbonamento, ecc. Si ottiene l'idea. Mi piacerebbe anche avere un modulo per consentire agli utenti di cambiare la loro password, indirizzo e-mail, informazioni personali sulla stessa pagina.

Il mio problema

dati dell'utente viene dal mio controller tramite una variabile del modello passato:

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

L'output è simile al seguente a mio avviso:

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

La forma in cui l'utente poteva modificare le sue informazioni avrebbe utilizzato un altro modello, ProfileModel. Quindi, a mio avviso, ho bisogno di utilizzare due modelli a mio avviso, uno per l'output delle informazioni e uno per la pubblicazione dei dati. Ho pensato che l'utilizzo di una vista parziale posso raggiungere questo obiettivo, ma ottengo questo errore:

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'.

Ecco cosa la mia chiamata alla vista parziale assomiglia:

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

     @Html.Partial("_ModifyProfileInfo") 
    } 

Ecco la vista parziale:

@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> 

E infine ecco il mio 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; } 
    } 

Mi manca qualcosa? Qual è il modo corretto per farlo?

Modifica: Ho rifatto il mio codice riflettendo la risposta di Nikola Mitev, ma ora ho un altro problema. Ecco l'errore che ottengo:

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

Ciò si verifica solo quando sto postando i valori degli indirizzi di posta elettronica modificati. Ecco il mio ViewModel (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; } 
    } 

Controller:

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

      var ProfileViewModel = new ProfileModel 
      { 
       UserObject = User 
      }; 

      return View(ProfileViewModel); 
     } 

E infine ecco la mia classe user.cs modello:

[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... 

Sto pensando che sta accadendo perché il modello è cercando di inserire i dati in ciascuna colonna required nel database.

Edit2: Il metodo HttpPost della mia azione Profil:

[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); 
      } 
     } 

risposta

35

Il modo migliore per gestire questa situazione è quello di utilizzare e trasmettere ViewModel al controller profilo, ViewModel è classe wrapper per più oggetti che si desidera passare alla vista.

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

Il controller dovrebbe essere simile:

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); 
} 

E infine la visualizzazione:

@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

Grazie, funziona come un fascino! :) +1 anche per la risposta molto ben scritta. – PeterInvincible

+0

Ho un altro errore ora :(Ho modificato la domanda per rispecchiarlo – PeterInvincible

+0

@Tharline il tuo particolare record che cerchi di recuperare ha valore nel campo LastName? –

13

C'è un sovraccarico di @Html.Partial, che consente di inviare ViewData come definito nel controller - questo è il metodo che di solito uso per viste parziali Nel controller definire ViewData["mypartialdata"] come ViewDataDictionary. Quindi secondo lei

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

Nella funzione profil [HttpPost], se modelstate.isvalid è falso, si torna la visualizzazione di modifica, ma devi definire nuovamente il tuo pmViewModel, altrimenti la tua vista parziale non avrà un oggetto da mostrare. Provare a utilizzare il seguente e fateci sapere cosa succede

[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

Grazie! In realtà ho dovuto inserire pmViewModel prima che qualsiasi visualizzazione venga restituita per farlo funzionare – PeterInvincible

+0

Stai dichiarando 'pmViewModel' e non viene mai usato, giusto? – SharpC

0

Anche se so che questa domanda è stato chiesto molto tempo fa, tuttavia alcune persone potrebbero ancora affrontare un problema simile. Una soluzione facile che uso per passare o avere più di un modello di visualizzazione su una pagina è utilizzare un ViewBag per contenere il secondo oggetto e fare riferimento ad esso nella vista. Vedi l'esempio qui sotto.

nel controller fare questo:

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; 

Quindi secondo lei queste proprietà diventano prontamente disponibili per voi

Problemi correlati