【问题标题】:How to let the post action method take a subobject of the original viewmodel as a parameter?如何让 post action 方法以原始 viewmodel 的子对象为参数?
【发布时间】:2011-04-22 13:32:32
【问题描述】:

这是我的模型:

public class IndexViewModel
{
    public FilterConditions conditions { get; set }
    public IEnumerable<SelectListItem> Countries { get; set }
}

public class FilterConditions
{
    public string condition11 { get; set }
    // ...
}

我有一个像这样的Index 操作方法:

public ActionResult Index()
{
    var model = new IndexViewModel();

    // fill the model here with default values

    return View(model);
}

视图呈现一个带有过滤条件的表单作为输入类型。

现在我希望通过该操作方法处理从该表单返回的帖子:

[HttpPost]
public ActionResult Index(FilterConditions model)
{
    // do some magic with model and return another view here
}

这确实有效(我在方法中放置了一个断点,它被调用),但我的模型的属性始终为空(默认值),而它们应该包含表单发布的值。

当我像这样修改动作方法时:

[HttpPost]
public ActionResult Index(IndexViewModel model)
{
    // do some magic with model.conditions and return another view here
}

一切正常,但这不是“正确的”(恕我直言),因为我不需要返回时的“国家”列表,我只需要选择的国家(这是条件之一)。

在不必将整个原始视图模型作为输入参数的情况下,有什么好的(最佳实践)方法来完成这项工作?

顺便说一句,我使用的是 ASP.NET MVC 2(我认为这并不重要,因为我认为这与 MVC 3 中的问题相同,但我并不完全确定)。

(我一直在互联网上寻找有关 asp.net mvc 中的下拉列表和视图模型的“最佳实践”,但我发现的不同建议并没有真正相互一致,而且很多内容也已经过时了.我没有找到一个“官方”的最佳实践。我希望我朝着正确的方向前进(将列表作为我的视图模型的一部分),如果我不是,请随时纠正我的问题。如果您知道的话,也请随时向我指出“认可的最佳实践”。)

更新

我发现我可以使用带有“filterconditions”前缀的 [Bind] 属性。这确实适用于这种观点。但是我最初的问题(我承认,它没有包含在我的问题中)没有解决。

碰巧这个特定的操作方法也是从另一个没有那个前缀的视图(它是一个 ajax 调用)调用的,在这种情况下它现在不再工作了。有什么建议吗?

【问题讨论】:

  • 听起来您想以两种方式称呼它...也许您可以每种方式都有一个参数,然后根据设置的值选择要使用的参数。
  • 您是使用 AjaxForm 进行 ajax 调用还是使用 jQuery ajax?
  • @nEEbz:我使用 jQuery ajax,但这没关系,因为我也有不使用 ajax 的问题。
  • 我觉得有点难以理解。如果是public ActionResult Index(IndexViewModel model),您是否尝试过仅发送过滤条件而不发送国家/地区?我认为模型绑定器将智能地仅绑定FilterConditions conditions 并将国家列表保留为空。
  • @nEEbz:我只发送条件。这实际上是通过表单的发布自动完成的,并且由于表单上的字段仅来自 filterConditions(模型的其他字段用于填充我的 DropDownLists),因此只会发送这些字段。我的问题是,如果我只指定 FilterConditions model 作为操作方法的参数,默认模型绑定器不会将它们解析为模型对象。但是,当我指定 FilterConditions filterConditions 时它确实有效(请参阅我的答案)。

标签: c# asp.net-mvc viewmodel


【解决方案1】:

我找到了解决办法。

显然,当我为参数变量使用与类型名称相同的名称时(大小写不必匹配),如下所示:

[HttpPost]
public ActionResult Index(FilterConditions filterConditions)
{
    // do some magic with model and return another view here
    // now the filterConditions variable actually contains values!
}

一切正常(我的 filterConditions 的值不再为空/null)。显然,默认的模型绑定器使用参数的名称作为绑定的潜在前缀。

我很高兴我发现了这一点,但如果在某处能更清楚地记录这一点,那就太好了。一点都不明显。

编辑: 根据要求:这是我认为的代码(aspx):

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

<%-- ... more stuff here ... --%>

<% using (Html.BeginForm())
   {%>
    <%= Html.ValidationSummary(true)%>

    <fieldset>
        <div class="editor-label">
            <%= Html.LabelFor(model => model.FilterConditions.Country)%>
        </div>
        <div class="editor-field">
            <%= Html.DropDownListFor(model => model.FilterConditions.Country, Model.Countries)%>
            <%= Html.ValidationMessageFor(model => model.FilterConditions.Country)%>
        </div>

        <div class="editor-label">
            <%= Html.LabelFor(model => model.FilterConditions.Make)%>
        </div>
        <div class="editor-field">
            <%= Html.TextBoxFor(model => model.FilterConditions.Make)%>
            <%= Html.ValidationMessageFor(model => model.FilterConditions.Make)%>
        </div>

        <%-- ... more fields inserted here ... --%>

        <p>
            <input type="submit" value="  Search...  " />
        </p>
    </fieldset>

<% } %>

【讨论】:

  • 您更改了参数的名称并开始工作?我可能会很烦人,您能否向我们展示您的表单/视图(其中包含 filterConditions 元素)。只是为了我们的学习目的。我一直认为 Model Binder 将元素(使用 name 属性)绑定到控制器参数名称。
  • @nEEbz:你去。更新了我的答案。
【解决方案2】:

嗨fretje:现在我可以用你的方式来解决你的问题,首先我有两个模型“IndexViewModel”和“Index”,以及DropDownList(没关系,只提供DropDown项目):

public class IndexViewModel : Index
{
   //public  int value { get; set; }
   public   List<System.Web.Mvc.SelectListItem> items { get; set; }
}

public class Index
{
    public int value { get; set; }
}


class DropDownList
{
   public List<System.Web.Mvc.SelectListItem> GetDropDownList()
   {
       List<System.Web.Mvc.SelectListItem> result = new List<System.Web.Mvc.SelectListItem>();
       result.Add(new System.Web.Mvc.SelectListItem
       {
           Value = "1",
           Text = "Apple"
       });
       result.Add(new System.Web.Mvc.SelectListItem
       {
           Value = "2",
           Text = "Milk"
       });
       return result;
   }
}

而两个Controller是Test()和Test(Models.Index),我通过IndexViewModel和回发IndexModel:

public ActionResult Test()
{
    var result =
        new Models.IndexViewModel
        {
            value = 1,
            items = new Models.DropDownList().GetDropDownList()
        };
    return View(result);
}
[HttpPost]
public ActionResult Test(Models.Index posatback)
{
    return View();
}

Test() 的视图是:

<% using (Html.BeginForm()) {%>
    <%: Html.ValidationSummary(true) %>        
    <fieldset>
        <legend>Fields</legend>            
        <div class="editor-field">
                    <%: Html.DropDownListFor(m=>m.value, Model.items )%>
        </div>            
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
<% } %>

这是工作!谢谢fretje,我又学到了一项技术。 :)


也许你可以试试

[HttpPost]
public ActionResult Index([Bind(Exclude="Countries")]IndexViewModel model)
{
    // do some magic with model.conditions and return another view here
}

嗨~ 您不需要将整个 SelectListItem 组合到 ViewModel,实际上您的 ViewModel 只有一个字段来存储用户的选择,整数或字符串,然后使用 DropDownListFor 像:

<%: Html.DropDownListFor(item.WeaponID, MyApplication.Models.DropDownList.GetDropDownList() )%>

请看我的博文,我用一个很简单的例子来解释: http://maidot.blogspot.com/2011/04/aspnet-mvc-viewdropdownlistfor.html

如果您有任何问题,请告诉我:)

【讨论】:

  • 据我了解,最佳实践是控制器应收集所有数据并将其传递给视图。在您的示例中,视图本身正在查询模型。我认为这不是在 ASP.NET MVC 中做事的正确方式。
  • 也可以同时传两个Model给View,一个是我们的ViewModel,一个是我们的List Model,就可以了。
  • @Maidot:这正是我的问题。要传递这两个模型,您必须将它们封装在包装类中(在我的情况下为DefaultViewModel),因此我的模型实际上是我的 defaultviewmodel 的子对象。
  • 对不起,我太笨了 :(,你试过 [Bind(Exclude="blah")]。但我不确定这是你想要的,因为它可能会将所有信息传递给服务器端。
  • @Maidot:我想要摆脱 DefaultViewModel 作为我的操作方法的参数。所以Exclude 不是我需要的。我确实发现我可以使用Prefix,但后来我遇到了另一个问题(请参阅我更新的问题)。
猜你喜欢
  • 2015-01-13
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
  • 2016-12-31
  • 2020-05-22
  • 1970-01-01
  • 2011-02-27
  • 1970-01-01
相关资源
最近更新 更多