MVC - 可能的多态视图绑定?

时间:2017-02-02 21:38:02

标签: c# asp.net-mvc

我可以在一个处理多个派生View类的MVC项目中有一个ViewModel吗?我目前正在使用ASP Core RC1目标4.5 .NET框架。

我的派生ViewModels具有使用数据注释实现的特定验证。如果我将派生的模型类对象传递给引用基本模型的View@model Models.BaseModel),则不会使用html 5 data-val标记向客户端呈现任何数据注释。

如果我使用强类型视图(@model Models.ChildModel),它会按预期工作。我不能在@model中使用多个View声明,因此我无法在View中检查模型的类型,并选择要渲染的模型类型。

,我想使用共享视图,因为有许多字段,只有验证实现需要根据使用的派生类进行更改。

以下是一个示例实现:

public abstract class BaseModel
{
    [Required]
    public abstract string FieldTest {get; set;}
}

public class ChildModel : BaseModel
{
    [Email]
    public override string FieldTest {get; set;}
}

public class AnotherChildModel : BaseModel
{
    [Phone]
    public override string FieldTest {get; set;}
}

这就是我想在View中实现的目标:

@if(Model is ChildModel)
{
    @model Models.ChildModel
}
else
{
    @model Models.AnotherChildModel
}

目前,我的最佳解决方案是为每个派生类视图模型提供单独的视图。问题是视图只是带有不同@model引用的重复..

5 个答案:

答案 0 :(得分:2)

  

目前,我最好的解决方案是每个都有一个单独的视图   派生类视图模型。问题在于视图   仅仅使用不同的@model引用重复..

似乎潜在的问题是你想要消除视图之间的重复代码。

如果是这样,您可以创建 部分视图 ,并在视图之间共享。

例如,

enter image description here

Edit.cshtml

@model UserCreateUpdateModel
@using (Html.BeginForm("Edit", "Users", FormMethod.Post))
{
    @Html.AntiForgeryToken()
    @Html.Partial("_CreateOrUpdate", Model)
}

Create.cshtml

@model UserCreateUpdateModel
@using (Html.BeginForm("Create", "Users", FormMethod.Post))
{
    @Html.Partial("_CreateOrUpdate", Model)
}

_CreateOrUpdate.cshtml

@model UserCreateUpdateModel
@if (Model.Id > 0)
{
   // Keep Edit only fields here, or place them in Edit.cshtml
}
else
{
   // Keep Create only fields here, or place them in Create.cshtml
}

// Keep shared fields for both Create and Edit mode

更新

我只是注意到您使用相同的属性用于不同的目的。请不要这样做。 它隐藏了对属性的确认 - 在ViewModel类以外的任何类中。维护将成为噩梦。

可以从BaseViewModel继承ViewModel(我们都这样做),但不是你覆盖它的方式。

我建议使用单独的属性 - public string Email {get; set;}public string Phone {get; set;}

public abstract class BaseModel
{
    [Required]
    public abstract string FieldTest {get; set;}
                            ^^^^^^^
}

public class ChildModel : BaseModel
{
    [Email]
    public override string FieldTest {get; set;}
                            ^^^^^^^
                          Store email
}

public class AnotherChildModel : BaseModel
{
    [Phone]
    public override string FieldTest {get; set;}
                            ^^^^^^^
                        Store phone number
}

答案 1 :(得分:0)

使用Interface而不是具体类型。一切都会好起来的......

我的意思是

你可以有一个类型接口的模型, 让我们说IBaseModel

@model IBaseModel
@using (Html.BeginForm("Create", "Users", FormMethod.Post))
{
    @Html.Partial("_CreateOrUpdate", IBaseModel)
}


// instead of this than all you need to do is cast to right model 
@if(Model is ChildModel)
{
    @model Models.ChildModel
}
else
{
    @model Models.AnotherChildModel
}

// in this case you will be able use both types and if your base class is implementing it you don't have to do much of refactoring.
IBaseModel as ChildModel.something 
IBaseModel as AnotherChildModel.something  

答案 2 :(得分:0)

可以使用基本类型,因为孩子可以这样引用, 我之前使用动态对象完成了这项工作。我假设您的模型位于顶部只是模型的一个示例,并不能真正代表最终产品。

@model basetype

@{
  dynamic testModel;
  if(Model.GetType().Name == typeof(ChildModel).Name)
       testModel = new ChildModel();
  else if(Model.GetType().Name == typeof(AnotherChildModel).Name)
       testModel = new AnotherChildModel();
}

您还可以使用一个标记或枚举来指示整个页面中的哪个孩子,以便在页面上更改详细信息。

我没有测试下面的内容,但如果只有两个选项,你甚至可以使用下面的内容:

var testModel = Model.getType().Name == typeof(ChildModel).Name ? new ChildModel() : new AnotherChildModel();

答案 3 :(得分:0)

您可以保持视图接受基本类型,即BaseModel。

 @model Models.BaseModel

在action方法中,您可以将动作中的ChildModel或AnotherChildModel类型对象发送到视图。由于两者都是BaseModel的派生类型,因此视图应该能够处理任何派生类型。你不必按照自己的方式和其他方式设置它。只需将其设置为基本类型即可。

OR

您还可以使用像EditorFor()这样的模板化视图帮助程序方法,这些方法正好适用于您希望将大量多态性转移到视图的情况。

您可以看到这个可能对您有帮助的链接 - Using a single view for derived mvc models

答案 4 :(得分:0)

模型是在控制器中设置的,因此理想情况下,只要模型来自/实现/实现@model,视图就不必关心它会获得哪个模型。为了处理根据哪个模型显示哪个视图,我发现最好的方法是使用基于模型名称显示的局部视图。

使用非抽象基础模型...

@model MyApp.Models.BaseModel
@using (Html.BeginForm...
{
    @Html.DisplayFor(model => model.BaseProperty)

    @await Html.PartialAsync(String.Concat("_", Model.GetType().Name, "SomePartial"), Model);
}

这要求遵循模型的零件的命名约定。因此SquirrelModel将在_SquirrelModelDetailsPartial.cshtml中显示其唯一属性,依此类推。这样就无需检查视图。 ChipmunkModel随后将触发_ChipmunkModelDetailsPartial.cshtml,依此类推。

我尝试了抽象/接口方法,但是在测试发布数据的控制器操作时遇到了问题。