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

时间:2013-06-18 15:42:21

标签: asp.net asp.net-mvc asp.net-mvc-4 model

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

我正在尝试做什么

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

我的问题

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

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

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

修改 我重新编写了反映Nikola Mitev答案的代码,但现在我还有另外一个问题。这是我得到的错误:

  

对象引用未设置为对象的实例。 (@ 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 个答案:

答案 0 :(得分: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 :(得分:13)

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

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

答案 2 :(得分:1)

[HttpPost]个合规性功能中,如果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);
    }
}

答案 3 :(得分: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;

然后在您看来,这些属性随时可供您使用