2

I'm 3 days into learning MVC for a new project and i've managed to stumble my way over the multitude of issues I've come across - mainly about something as simple as moving data to a view and back into the controller in a type-safe (and manageable) manner. This is the latest.

I've seen this reported before but nothing advised has seemed to work. I have a complex view model:

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

This maps to (the main Index page):

%@ 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>

and a 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>

This is returned to the following method:

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

My problem is that when the view model is rehydrated from the View into the ViewModel, the SearchFragment elements are null. I suspect this is because the default model binder doesn't realise the HTML ItemId and Identifier elements rendered inline in the View map to the SearchFragment class. When I have two extra properties (ItemId and Identifier) in the IndexViewModel, the values are bound correctly.

Unfortunately, as far as I can tell, I must use the SearchFragment as I need this to strongly type the Search UserControl... as the control can be used anywhere it can operate under any parent view.

I really don't want to make it use "magic strings". There's too much of that going on already IMO.

I've tried prefixing the HTML with "Search." in the hope that the model binder would recognise "Search.ItemId" and match to the IndexViewModel "Search" property and the ItemId within it, but this doesn't work.

I fear I'm going to have to write my own ModelBinder to do this, but surely this must be something you can do out-of-the-box??

Failing that is there any other suggestions (or link to someone who has already done this?)

Here's hoping....


Thanks so far. It's pretty obvious this fairly basic requirement is missing from MVC :p

4

3 回答 3

1

我想你的问题可能在这里:

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

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

编辑:

我刚刚注意到:

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

应该:

<%= Html.TextBox("Search.Identifier", Model.Identifier)%
于 2010-02-06T20:48:22.287 回答
0

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

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

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

于 2010-02-08T09:02:44.323 回答
0

我的第一个想法是 SearchFragment 的属性与表单字段的大小写不同。

我可能错了,但可能值得检查。

编辑

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

于 2010-02-08T09:18:02.723 回答