在单个视图中使用MVC 5多个模型

11

能否请提供一个将两个模型合并到一个视图中的示例?

目前,我有一个名为 RecordCard 的页面,其中包含:

@model IEnumerable<WebApplication1.Models.Weight>

下面的代码是在 AccountController 中提供的:

public ActionResult RecordCard()
{
    var UserId = User.Identity.GetUserId();
    var weightModel = from m in db.Weights where m.UserId == UserId select m;
    return View(weightModel);
}

记录卡页面还包含一个表单,该表单与以下类绑定:
public class AddWeightModel
{
    [Required]
    [DataType(DataType.Text)]
    [Display(Name = "Stone")]
    public Nullable<short> Stone { get; set; }

    [Required]
    [DataType(DataType.Text)]
    [Display(Name = "Pound")]
    public Nullable<short> Pound { get; set; }
}

然而,这是两个不同目的的独立模型,那么我如何将它们组合成一个包含IEnumerable列表和一组表单元素的单个模型,最终可以使用以下代码正确地将记录添加到数据库中:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RecordCard(Weight Model)
{
    if (ModelState.IsValid)
    {
        using (WebApplication1Entities db = new WebApplication1Entities())
        {
            Weight weight = new Weight();
            weight.UserId = User.Identity.GetUserId();
            weight.Stone = Model.Stone;
            weight.Pound = Model.Pound;
            weight.Date = System.DateTime.Now;

            db.Weights.Add(Model);
            db.SaveChanges();
        }
    }
    return View(Model);
}

我已经包含了下面的Weight类:

我已经包含了下面的Weight类:

public partial class Weight
{
    public int Id { get; set; }
    public string UserId { get; set; }
    public Nullable<short> Stone { get; set; }
    public Nullable<short> Pound { get; set; }
    public Nullable<System.DateTime> Date { get; set; }
}

这里还有一个WebApplication1Entities类,它将Weight表声明为Weights:

public partial class WebApplication1Entities : DbContext
{
    public WebApplication1Entities()
        : base("name=WebApplication1Entities")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual DbSet<Weight> Weights { get; set; }
}

请解释需要如何进行修改,无论我尝试阅读、跟随和实现什么,似乎总是缺少某些东西。 任何帮助都将不胜感激 :-)

你可能想尝试一下MVVM方法,我已经添加了一个带有示例的答案。 - brainless coder
3个回答

15

我认为这是使用ViewModel的好例子。 我建议这样做 -

创建一个由这两个类组成的ViewModel

public class AddWeightModel
{
    [Required]
    [DataType(DataType.Text)]
    [Display(Name = "Stone")]
    public Nullable<short> Stone { get; set; }

    [Required]
    [DataType(DataType.Text)]
    [Display(Name = "Pound")]
    public Nullable<short> Pound { get; set; }
}
....
public partial class Weight
{
    public int Id { get; set; }
    public string UserId { get; set; }
    public Nullable<short> Stone { get; set; }
    public Nullable<short> Pound { get; set; }
    public Nullable<System.DateTime> Date { get; set; }
}
.....
public class WeightViewModel
{
    public IList<AddWeightModel> AddWeightModel { get; set; }
    public Weight Weight { get; set; }
}

那么请将您的观点转变为接受视图模型 -

@model WeightViewModel

最后修改你的控制器以适应这个变化 -

public ActionResult RecordCard()
    {
        var UserId = User.Identity.GetUserId();
        var weightModel = from m in db.Weights where m.UserId == UserId select m;
        var viewModel = new WeightViewModel
        {
            Weight = weightModel,
            AddWeightModel = new List<AddWeightModel>(){}
        };
        return View(viewModel);
    }

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RecordCard(WeightViewModel viewModel)
{
    Weight Model = viewModel.Weight;
    if (ModelState.IsValid)
    {
        using (WebApplication1Entities db = new WebApplication1Entities())
        {
            Weight weight = new Weight();
            weight.UserId = User.Identity.GetUserId();
            weight.Stone = Model.Stone;
            weight.Pound = Model.Pound;
            weight.Date = System.DateTime.Now;

            db.Weights.Add(Model);
            db.SaveChanges();
        }
    }
    return RedirectToAction("RecordCard");
}

请查看我的修改后的帖子,因为我已经有一个用于 IEnumerable 列表的 Weight 类。 - iggyweb
这不是一个新的类,它们都是你提到的类,因此根据你的需要进行编辑,我向你展示了如何传递多个模型并将它们绑定。所以它们只是例子。不过,我已经编辑了答案。 - brainless coder
好的,我开始明白了,对不起我的愚蠢,我是新手。在Weight = weightModel这一行下面有红色的下划线,而且使用List来声明表单字段,IEnumerable用于记录列表吗? - iggyweb
我使用 @Html.TextBoxFor(AddWeightModel => AddWeightModel.Weight.Pound, new { @placeholder = "Pound *", @type = "text" }) 来处理表单元素,这样做是正确的吗?我没有看到任何红色下划线,太好了。 - iggyweb
我找到了为什么红线出现在“Weight = weightModel”这一行的原因,因为它期望的是IEnumerable,所以我已经修改了WeightViewModels,如下:public IList<AddWeightModel> AddWeightModel { get; set; } public IEnumerable<Weight> ListWeight { get; set; } public Weight Weight { get; set; }。我的代码中没有更多的红线,项目已编译,但现在我遇到了错误:“传递给字典的模型项的类型为'WebApplication1.Models.Weight',但此字典需要一个模型项的类型为'WebApplication1.Models.WeightViewModel'”。 - iggyweb
显示剩余4条评论

9
我之前已经解决过这个问题,并想到了一种优秀的解决方案。
首先,您需要设置主要类来发送,以及一个“持有者”类来存储它们,最终发送到视图。 正如您可能发现的那样,这是因为视图无法将多个模型发送给它。
public class WebsiteTheme
{
    public string Color { get;set; }
    public string Title { get;set; }

    public WebsiteTheme() {
         Color = "blue";
         Title = "test website";
    }
}

public class User
{
    public string Name { get;set; }
    public string Gender { get;set; }

    public User() {
         Name = "Anonymous";
         Gender = "Unspecified";
    }
}

public class ToPage
{
    public WebsiteTheme WebsiteTheme{ get; set; }
    public User User { get; set; }

    public ToPage() {
         websiteTheme = new WebsiteTheme();
         user = new User();
    }
}

这将允许您向页面发送任意数量的类。

然后,在您的控制器中,您需要填充这些类。确保首先初始化它们,然后将填充的类设置为您的 holder 类。

WebsiteTheme websiteTheme = new WebsiteTheme();
websiteTheme.Color = "orange";

User user = new User();
user.Name = "Darren";

ToPage toPage = new ToPage();
toPage.User = user;
toPage.WebsiteTheme = websiteTheme;

return View(toPage);

在你的看法中,你可以以任何方式称呼它们。但请确保在每种情况下都使用HolderModel.SpecifiedModel

@model WebApplication1.Models.ToPage

@Html.DisplayFor(model => model.User.Name)

1
很好的无杂乱回答,非常简明地解释了它。被接受的答案对于问题来说是完美的,但你的答案最终将帮助更多的人。 - rory

1
我做了一个类似这样的复合模型:

public class CompoundModel 
{
    public SearchModel SearchModel { get; set; }
    public QueryResultRow ResultModel { get; set; }
}
public class QueryResultRow
{
    [DisplayName("Id")]
    public long id { get; set; }
    [DisplayName("Importdatum")]
    public System.DateTime importdate { get; set; }
    [DisplayName("Mandant")]
    public int indexBMClient { get; set; }
}

public class SearchModel 
{
    [Required]
    [DataType(DataType.Date)]
    [Display(Name = "Zeitraum von")]
    public DateTime dateFrom { get; set; }
    [Display(Name = "Terminal-ID")]
    public string tid { get; set; }
    [Display(Name = "Belegnummer")]
    public string receiptnumber { get; set; }
}

在视图头部:
@model MyProject_aspmvc.Models.CompoundModel

从SearchModel获取数据访问,例如:
model => model.SearchModel.tid

例如,从ResultModel获取数据访问:

model => model.ResultModel.importdate 

为什么您会在视图头中使用ReceiptCompoundModel,而在模型中使用不同的名称? - Ken-F

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接