你能从MVC 3中的强类型模型中删除HTML字段前缀吗?

时间:2012-01-26 23:06:54

标签: asp.net-mvc asp.net-mvc-3 model-view-controller view

我有一个这样的视图模型:

public class EditVM
{
  public Media.Domain.Entities.Movie Movie       { get; set; }
  public IEnumerable<Genre>          Genres      { get; set; }
}

电影是我想要编辑的真实实体。类型只是为了填充下拉列表。我打电话的时候我更喜欢这个:

@Html.TextBoxFor(m => m.Movie.Title)

在我的强类型视图中,输入控件的名称为"Title",而不是"Movie.Title"

我不希望使用ViewData或类似内容将我的视图拆分为部分视图或丢失强类型视图。

有没有办法向View表达我不希望拥有Movie.前缀?我注意到你可以设置:

ViewData.TemplateInfo.HtmlFieldPrefix = "x";

在控制器中,但不幸的是,似乎只允许添加附加前缀。将其设置为""不会做任何事情。

这有什么工作吗?或者,如果我希望保留强类型视图和lambdas,我是否会遇到在这种情况下并非真正必要的不幸前缀?

感谢您的帮助。

更新

这是控制器的动作,可能会让事情更清晰。

public ActionResult Edit(int? id)
{
  var vm = new EditVM
  {
    Movie  = id.HasValue ? _movieSvc.Find(id.Value) : new Movie(),
    Genres = AppData.ListGenres()     
  };
  return View(vm);
}

[HttpPost]
public void Edit([Bind(Prefix = "Movie")]Movie m)
{
   _movieSvc.AddOrUpdateMovie(m); //Exceptions handled elsewhere
}

3 个答案:

答案 0 :(得分:5)

不,为了做你想做的事,你必须重写Html助手,然后你必须编写自己的模型绑定器。似乎很多工作都是为了获得最低收益。

唯一的选择是将Movie对象作为模型传递的Partial视图。但是,这需要您编写自己的模型绑定器才能识别它。

您必须执行m.Movie.Title的原因是ID具有正确的名称,因此模型绑定器可以将其识别为模型的成员。

根据您的更新:

您的选择是:

  1. 使用非强类型帮助程序。
  2. 使用局部视图。
  3. 重写stronly类型的助手
  4. 根本不要使用帮助程序,并将值写入HTML
  5. 就个人而言,我只使用1或2,可能是2。

    编辑:

    根据您的上述更新。将代码更改为此(请注意,Genres不会回发到服务器,因此m.Genres在回发时将为null):

    [HttpPost] 
    public void Edit(EditVM m) 
    { 
       _movieSvc.AddOrUpdateMovie(m.Movie); //Exceptions handled elsewhere 
    } 
    

    编辑:

    我想到了另一种选择。你可以这样做:

    @{ var Movie = Model.Movie; }
    @Html.TextBoxFor(m => Movie.Title)
    

    但是,如果出现验证错误,则必须重新创建EditVM。

答案 1 :(得分:1)

  

我有一个像这样的视图模型

我认为你可能对视图模型有什么误解。视图模型不应包含对您的域模型的任何引用,这些引用似乎是MovieGenre类。我的意思是创建一个后缀为VM的新类,并将所有域模型填充为属性并不是视图模型。视图模型是专门为满足视图要求而设计的类。

更正确的视图模型如下所示:

public class EditVM
{
    public string MovieTitle { get; set; }
    public IEnumerable<GenreViewModel> Genres { get; set; }
}

并且在您看来,您将拥有:

@Html.EditorFor(x => x.MovieTitle)
@Html.EditorFor(x => x.Genres)

答案 2 :(得分:1)

另一个选择是使用TextBox(string name, object value)重载而不是TextBoxFor

@Html.TextBox("Title", Model.Movie.Title)

您也可以指定输入标记HTML而不是使用帮助程序。

另一种选择是将EditVM作为回发参数。这就是我要做的。我的post动作参数始终与.cshtml模型的类型相同。是的,会有像列表这样的属性为null,但你只是忽略它们。它还允许您优雅地处理发布错误,因为如果出现错误,您无论如何都需要返回该视图模型的实例,并且包含它们提交的值。我通常使用私有方法或DB层来处理检索进入ViewModel的各种列表,因为这些列表在回发时将为空,并且需要重新填充,而不会触及帖子中的属性。

使用现在的post方法,如果需要返回相同的视图,则必须创建一个新的EditVM,然后将任何已发布的值复制到其中,并仍然填充列表。使用我的方法,您可以消除其中一个映射步骤。如果您要发布多个内容,您的帖子操作中是否会有多个不同的参数?让它们自然地进入一个键入视图EditVM的参数。虽然在回发过程中可能在VM中具有那些空属性感觉很棘手,但是在View和回发IMO之间可以获得良好的可预测一致性。您不必花费大量时间考虑post方法中的哪些参数组合将从表单中获取所有数据。