2009-11-30 127 views
0

我在玩ASP.NET MVC应用程序,并且遇到了一些问题。我对ASP.NET MVC相当陌生,并且几乎不了解在这一点上让事情起作用的基础知识。ASP.NET MVC:绑定到多个模型

我有一个PersonModel,PersonController和一堆视图,让用户添加一个新人,编辑一个人并搜索人。

我没有在后端使用数据库。我所做的一切都依赖于返回“person”结构的外部DLL(我将其转变为PersonModels)。

为了搜索人员,我必须提供一个人员结构作为外部DLL中的方法的搜索条件。该方法返回一组符合搜索条件的人员结构。如果我想检索系统中的所有人员,则为该方法提供一个空的人员结构。

所以,我有“检索所有人”功能工作.....但我想提供高级搜索。

我搜索查看被绑定到包含2个属性的类:

Public Class PersonSearchModel 
    Private _searchCriteria As PersonModel 
    Private _searchResults As List(Of PersonModel) 
    Public Property SearchCriteria As PersonModel 
    Get 
     return _searchCriteria 
    End Get 
    Set(ByVal value As PersonModel) 
     _searchCriteria = value 
    End Set 
    End Property 
    Public Property SearchResults As List(Of PersonModel) 
    Get 
     return _searchResults 
    End Get 
    Set(ByVal value As List(Of PersonModel)) 
     _searchResults = value 
    End Set 
    End Property 
End Class 

现在搜索查看绑定到这个PersonSearchModel和我有2段......一个部分,在那里用户可以提供搜索条件,显示搜索结果的部分。

我有一个问题,将PersonSearchModel.SearchCriteria绑定到用于显示/收集Person搜索条件的控件。

我无法检索搜索条件。

这是我在我的搜索标准视图:

<fieldset> 
     <legend>Search Criteria</legend> 
     <% 
      With Model.SearchCriteria 
     %> 
     <div style="float:left"> 
     <p> 
      <label for="FirstName"> 
       FirstName:</label> 
      <%=Html.TextBox("FirstName", Html.Encode(.FirstName))%> 
      <%= Html.ValidationMessage("FirstName", "*") %> 
     </p> 
     <p> 
      <label for="LastName"> 
       LastName:</label> 
      <%=Html.TextBox("LastName", Html.Encode(.LastName))%> 
      <%= Html.ValidationMessage("LastName", "*") %> 
     </p> 
     <!-- More controls --> 
     </div> 
     <% End With%> 
    </fieldset> 
    <%=Html.ActionLink("Search", "Search",Model.SearchCriteria)%> 
<!-- The Search Results Section--> 

的PersonModel传递到搜索方法是一种新的/空PersonModel对象。 它不包含用户输入的数据。

我在这里做错了什么?

********** 编辑 ********** 我试着改变视图来进行不同的绑定。我删除了VB“With”:

<fieldset> 
     <legend>Search Criteria</legend> 
     <div style="float:left"> 
     <p> 
      <label for="FirstName"> 
       FirstName:</label> 
      <%=Html.TextBox("FirstName", Html.Encode(.FirstName))%> 
      <%= Html.ValidationMessage("FirstName", "*") %> 
     </p> 
     <p> 
      <label for="LastName"> 
       LastName:</label> 
      <%=Html.TextBox("LastName", Html.Encode(.LastName))%> 
      <%= Html.ValidationMessage("LastName", "*") %> 
     </p> 
     <!-- More controls --> 
     </div> 
    </fieldset> 
    <%=Html.ActionLink("Search", "Search",Model.SearchCriteria)%> 
<!-- The Search Results Section--> 

但是这并没有帮助。

我也试过:

<fieldset> 
     <legend>Search Criteria</legend> 
     <div style="float:left"> 
     <p> 
      <label for="FirstName"> 
       FirstName:</label> 
      <%=Html.TextBox("Model.SearchCriteria.FirstName", Html.Encode(Model.SearchCriteria.FirstName))%> 
      <%= Html.ValidationMessage("FirstName", "*") %> 
     </p> 
     <p> 
      <label for="LastName"> 
       LastName:</label> 
      <%=Html.TextBox("Model.SearchCriteria.LastName", Html.Encode(Model.SearchCriteria.LastName))%> 
      <%= Html.ValidationMessage("LastName", "*") %> 
     </p> 
     <!-- More controls --> 
     </div> 
    </fieldset> 
    <%=Html.ActionLink("Search", "Search",Model.SearchCriteria)%> 
<!-- The Search Results Section--> 

和:

<fieldset> 
     <legend>Search Criteria</legend> 
     <div style="float:left"> 
     <p> 
      <label for="FirstName"> 
       FirstName:</label> 
      <%=Html.TextBox("SearchCriteria.FirstName")%> 
      <%= Html.ValidationMessage("FirstName", "*") %> 
     </p> 
     <p> 
      <label for="LastName"> 
       LastName:</label> 
      <%=Html.TextBox(".SearchCriteria.LastName")%> 
      <%= Html.ValidationMessage("LastName", "*") %> 
     </p> 
     <!-- More controls --> 
     </div> 
    </fieldset> 
    <%=Html.ActionLink("Search", "Search",Model.SearchCriteria)%> 
<!-- The Search Results Section--> 

不过,我仍然得到传递到控制器中的搜索方法的空/新PersonModel。我也检查了PersonSearchModel.SearchCriteria,看看是否包含输入的值,但也有一个新的/空的PersonModel。

-Frinny

回答

0

使用反射几乎什么MVC模型粘合剂设置做的,我的猜测是,你没有正确命名你的领域,所以当他们回发到你的行动,他们没有地图直到你的参数。尝试做类似:

Function Search(ByVal personSearchModel As PersonSearchModel, ByVal collection As FormCollection) As ActionResult 

然后你的字段(HTML)应该被命名为像这样:

<%= Html.TextBox("personSearchModel.SearchCriteria.FirstName", Html.Encode(Model.SearchCriteria.FirstName)) %> 
+0

不知道你在这里得到什么。我对你选择的变量名有点困惑......变量名与类型匹配。所以我不确定你是否试图告诉我匹配变量名称的字段名称,或者如果你告诉我匹配的对象类型。我会尝试两种方式,看看会发生什么。谢谢您的回复。 – Frinavale 2009-12-08 14:51:23

+0

非常感谢你马特。事实证明,它是必须匹配的变量名称。 我应该拿起一本关于这个话题的书,而不是先试着用手去做。再次感谢! – Frinavale 2009-12-08 14:55:52

+0

我正在看我的其他视图(编辑和创建),我没有在这些视图的字段名称中指定变量名称......但我仍然得到一个完全填充的人物对象作为参数传入到“创建”或“编辑”方法。这是为什么? – Frinavale 2009-12-08 14:58:56

0

我认为你缺少的调用Html.TextBox和Html.ValidationMessage必要的前缀。我推荐而不是使用VB的“With”关键字,因为它掩盖了成员的全名。 HTML帮助程序和模型绑定(用于将参数传递到操作方法中)都需要属性或字段的全名以检索值。

试试这个:

<%= Html.TextBox("SearchCriteria.FirstName", SearchCriteria.FirstName) %> 
<%= Html.ValidationMessage("SearchCriteria.FirstName", "*") %> 

此外,还有不需要调用了Html.Encode()的值被传递到文本框 - 它就会自动反正编码。

+0

我删除了VB.NET,并尝试了你推荐的代码。我也试过<%= Html.TextBox(“Model.SearchCriteria.FirstName”,Model.SearchCriteria.FirstName)%>但这没有帮助。我仍然没有改变任何东西:我仍然在搜索方法中得到一个新的/空的PersonModel。 – Frinavale 2009-12-02 19:35:07

+0

您应该只能使用Html.TextBox(“SearchCriteria.FirstName”)(不要在字符串前添加“Model”,也不需要传入显式值--TextBox助手会自动检索它。 – Eilon 2009-12-05 05:05:29

+0

控制器仍在接收空的/新的PersonMode。请参阅原始问题,因为我已将其更新为包含我曾尝试的其他内容。 – Frinavale 2009-12-07 14:35:27

0

经过多次测试和调试后,我发现了一些有趣的东西:我可以从传递给搜索函数的FormCollection中检索用户输入的信息。最初我的搜索功能需要2个参数。第一个参数是假定绑定到PersonSearchModel.SearchCriteria的PersonModel,第二个参数是视图的FormCollection。

我能够根据传递给Search函数的FormCollection创建用于PersonSearchModel.SearchCriteria的PersonModel。我删除了第一个参数(PersonModel),因为它总是一个新的/空的对象。

这是我目前的搜索方法:

<AcceptVerbs(HttpVerbs.Post)> _ 
Function Search(ByVal collection As FormCollection) As ActionResult 
     Dim searchModel As New SearchPersonsModel 

     Dim personProperties() As PropertyInfo = GetType(PersonModel).GetProperties 
     For Each pi As PropertyInfo In personProperties 
      Dim piName As String = pi.Name 
      Dim info As String = Array.Find(collection.AllKeys, Function(x) x.Compare(piName, x, true) = 0) 
      If String.IsNullOrEmpty(info) = False Then 
       pi.SetValue(searchModel.SearchCriteria, collection.Item(info), Nothing) 
      End If 
     Next 
'The following code uses the searchModel.searchCriteria to search for People. 
End Function 

我的视图(如果你好奇)看起来像:

<% Using Html.BeginForm()%> 
<%With Model.SearchCriteria%> 
    <fieldset> 
    <legend>Search Criteria</legend> 
     <div style="float: left"> 
     <p> 
      <label for="FirstName">FirstName:</label> 
      <%=Html.TextBox("FirstName", Html.Encode(Model.SearchCriteria.FirstName))%> 
      <%=Html.ValidationMessage("Model.SearchCriteria.FirstName", "*")%> 
     </p> 
     <p> 
      <label for="LastName">LastName:</label> 
      <%=Html.TextBox("LastName", Html.Encode(Model.SearchCriteria.LastName))%> 
      <%=Html.ValidationMessage("Model.SearchCriteria.LastName", "*")%> 
     </p> 
     <!---..... more controls .... --> 
    </div> 
    </fieldset> 
    <%End With%> 
    <input type="submit" value="Search" /> 

<!-- Search Results Controls --> 

    <%End Using%> 

该解决方案的工作,但我真的不喜欢它。 为什么我必须重新创建用作搜索条件的PersonModel? 为什么我不能将此对象作为参数传递给搜索方法?

-Frinny

0

好像的UpdateModel()可能在这里你的朋友。 MVC不会传递Web窗体风格的对象。

即使您的模型包含两个对象,也很可能使用UpdateModel来检索其中一个对象的值。您只需将该对象指定为参数即可。例如:

Thing t = new Thing(); 
UpdateModel(t); 

您可能必须查看参数名称以允许MVC正确猜测。 此外,出于安全原因和/或为了逃避过分敏锐的模型验证,您可能必须列入白名单。

+0

我试过这个,但它仍然没有工作。我查了一下UpdateModel方法,它看起来应该可以工作......但由于某种原因它仍然传回一个新的/空的对象。 – Frinavale 2009-12-08 14:52:35