ASP.MVC 1.0复杂的ViewModel没有填充Action

时间:2010-02-06 20:41:36

标签: asp.net-mvc viewmodel modelbinder

我在为一个新项目学习MVC已经有3天了,我已经成功地遇到了我遇到的众多问题 - 主要是关于将数据移动到视图并返回到控制器以类型安全(和可管理)的方式。这是最新的。

我以前见过这个报道,但没有任何建议似乎有效。我有一个复杂的视图模型:

public class IndexViewModel : ApplicationViewModel
{
 public SearchFragment Search { get; private set; }

 public IndexViewModel()
 {
  this.Search = new SearchFragment();
 }
}
public class SearchFragment
{
 public string ItemId { get; set; }
 public string Identifier { get; set; }
}

这映射到(主索引页面):

%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IndexViewModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <% Html.BeginForm("Search", AvailableControllers.Search, FormMethod.Post); %>
    <div id="search">
        <% Html.RenderPartial("SearchControl", Model.Search); %>
    </div>
    <% Html.EndForm(); %>
</asp:Content>

和UserControl:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SearchFragment>" %>

<p>
    <label for="itemId">
        <%= Html.Resource("ItemId") %></label>
    <%= Html.TextBox("itemId", Model.ItemId)%>
</p>
<p>
    <label for="title">
        <%= Html.Resource("Title") %></label>
    <%= Html.TextBox("identifier", Model.Identifier)%>
</p>
<p>
    <input type="submit" value="<%= Html.Resource("Search") %>" name="search" />
</p>

这将返回到以下方法:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Search(IndexViewModel viewModel)
{
 ....
}

我的问题是,当视图模型从View重新水化为ViewModel时,SearchFragment元素为null。我怀疑这是因为默认模型绑定器没有实现在SearchFragment类的View映射中内联呈现的HTML ItemId和Identifier元素。当我在IndexViewModel中有两个额外的属性(ItemId和Identifier)时,这些值被正确绑定。

不幸的是,据我所知,我必须使用SearchFragment来强烈输入Search UserControl ...因为控件可以在任何父视图下运行的任何地方使用。

我真的不想让它使用“魔术字符串”。 IMO已经有太多的事情发生了。

我尝试使用“搜索”为HTML添加前缀。希望模型绑定器能够识别“Search.ItemId”并匹配IndexViewModel“搜索”属性和其中的ItemId,但这不起作用。

我担心我必须编写自己的ModelBinder才能做到这一点,但这肯定是你可以开箱即用的东西吗?

如果没有其他建议(或链接到已经完成此操作的人?)

这是希望......


到目前为止,谢谢。很明显,MVC缺少这个相当基本的要求:p

3 个答案:

答案 0 :(得分:1)

我认为您的问题可能就在这里:

public IndexViewModel()
{
  this.Search = new SearchFragment();
}

您是否尝试将Search属性保留为null?我知道DefaultModelBinder中的CreateModel受保护方法不会触发,除非该值已经为null,但我不确定是否设置了属性。如果你还没有尝试过那就试一试......

修改

我刚注意到:

<%= Html.TextBox("identifier", Model.Identifier)%

应该是:

<%= Html.TextBox("Search.Identifier", Model.Identifier)%

答案 1 :(得分:0)

也许您应该尝试将操作方法​​更改为类似的方法并手动执行绑定:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Search(FormCollection formCollection)
{
   var viewModel = new IndexViewModel();
   viewModel.Search.ItemId = formCollection[0];
   viewModel.Search.Identifier = formCollection[1];
   ...
}

但这种方法有点类似于创建自己的活页夹。

答案 2 :(得分:0)

我的第一个想法是SearchFragment的属性与表单字段的情况不同。

我可能错了,但可能值得一试。

修改

在进一步的调查中,您可能还需要考虑表单使用SearchFragment但View使用IndexViewModel的事实 - 为什么不使用SearchFragment作为ViewModel?