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 プロパティを null のままにしてみましたか? 値が既に null でない限り、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 を使用しているという事実も考慮する必要があるかもしれません。

于 2010-02-08T09:18:02.723 に答える