首页 文章

MVC 4 - 在局部视图中使用不同的模型

提问于
浏览
29

请忍受我的noobness,我是MVC模式的新手 .

What I'm trying to do

我正在为我的网站上的注册用户构建 Profiles 信息页面 . 此页面将列出有关用户的数据,例如出生日期,电话号码,订阅状态等 . 您明白了 . 我还希望有一个表格让用户更改他们的密码,电子邮件地址,个人信息 on the same page .

My problem

用户的数据来自我的控制器通过传递的模型变量:

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我需要在我的视图中使用两个模型,一个用于输出信息,一个用于发布数据 . 我认为使用局部视图我可以实现这一点,但我得到了这个错误:

传递到字典中的模型项的类型为“Applicense.Models.User”,但此字典需要“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; }
    }

我错过了什么吗?这样做的正确方法是什么?

Edit: 我重新编写了反映Nikola Mitev的代码's answer, but now I have another problem. Here' s我得到的错误:

对象引用未设置为对象的实例 . (@ Model.UserObject.LastName)

仅当我发布更改的电子邮件地址值时才会出现这种情况 . 这是我的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; }
    }

控制器:

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

4 回答

  • 37

    处理这种情况的最佳方法是使用viewModel并将其传递给Profile控制器,viewModel是您要传递给视图的多个对象的包装类 .

    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>
    }
    
  • 1

    @Html.Partial 的重载允许您按照控制器中的定义发送 ViewData - 这是我通常用于部分视图的方法 . 在您的控制器中将 ViewData["mypartialdata"] 定义为 ViewDataDictionary . 然后在你看来

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

    [HttpPost] profil函数中,如果 modelstate.isvalid 为false,则返回编辑视图,但需要再次定义 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

    虽然我知道很久以前就已经问过这个问题但是有些人可能仍会面临类似的问题 . 我用来在页面上传递或拥有多个视图模型的一个简单解决方案是使用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;
    

    然后在您的视图中,您可以随时使用这些属性

相关问题