【问题标题】:Adding dynamically added controls to the ViewModel将动态添加的控件添加到 ViewModel
【发布时间】:2015-07-01 13:56:21
【问题描述】:

我有以下 ViewModel,其中填充了一些预定义的数据。其中一个预定义数据是 ApplicationParameter ViewModels 列表,它被设置为最初显示 n 个 ApplicationParameters。

我想要实现的是允许用户在单击按钮时添加额外数量的 ApplicationParameters ViewModel,这是我通过使用 ApplicationParameter 代码调用 PartialView 实现的。正如预期的那样,控件会自动添加,但在 ViewModel 中无法识别,因为它们没有正确的命名(因为它们是嵌套的)。

如何使动态添加的控件对 POST 返回的 ViewModel 可见。

视图模型

public class ApplicationVM
{

    public int idApplication { get; set; }
    public int idCompany { get; set; }
    public string Company { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string Link { get; set; }
    public string Photo { get; set; }

    public List<ApplicationParameterVM> ApplicationParameters { get; set; }
}

public class ApplicationParameterVM
{
    public string Name { get; set; }
    public bool Keep { get; set; }
}

动作视图(代码 sn-p)

 <tbody id="editorRows">
     @for (int i = 0; i < Model.ApplicationParameters.Count(); i++)
         {
            <tr>
                <td>
                    @Html.TextBoxFor(m => Model.ApplicationParameters[i].Name, new { @class = "form-control" })
                     @Html.CheckBoxFor(m => Model.ApplicationParameters[i].Keep)
                  </td>
              </tr>
           }
   </tbody>

添加ApplicationParameterVM的动作视图

   @model AccessMarketmind.Areas.Administration.ViewModels.ApplicationParameterVM
   @{
        Layout = null;
    }

<tr class="application-parameters">
     <td>
         @Html.TextBoxFor(m => Model.Name, new { @class = "form-control" })
         @Html.CheckBoxFor(m => Model.Keep)
     </td>
</tr>

我知道这个看起来微不足道,可以使用 Javascript 轻松完成,但问题是我有更复杂的 ViewModel(阅读:重嵌套),其中 Javascript 不是一个选项。

【问题讨论】:

  • 我不明白为什么您仍然需要“添加 ApplicationParameterVM 的操作视图”。
  • @Sravan 也许我不够清楚,操作用于创建 ApplicationVM。由于 ApplicationParameters 是 ViewModel 的一部分,因此我在操作中需要它们。简而言之,我省略了不必要的代码。
  • 您需要使用BeginCollectionItem 助手,或者对于纯客户端方法,refer this answer
  • @StephenMuecke 感谢您的回答,我将采用客户端方法,因为目前它是实现所需结果的更快方法。
  • 它肯定会提供更好的性能(无需使用 ajax 并调用服务器来返回部分视图),但请记住,它有点难以维护 - 如果您更改或添加属性,甚至更改或在属性上添加验证属性,您还需要更新模板:)

标签: c# asp.net-mvc viewmodel


【解决方案1】:

这类动态表单的基本技巧是发布的表单数据应与属性名称匹配。

例如:您的动态控件数组的最终属性名称应该是。 ApplicationParameters[0].Name 和 ApplicationParameters[0].Keep 和
ApplicationParameters[1].Name 和 ApplicationParameters[1].Keep .....

要实现这一点,请仅使用松散耦合的帮助器 Html.TextBox()。

【讨论】:

  • 我认为我可以使用您的代码获取帖子上的数据,因为 ApplicationParameters 是应用程序视图模型的一部分。另外,一个子问题,如果我们有一个多级嵌套怎么办 - 在这种情况下它只有一层但是如果我们有 Application.ApplicationParameter[0].ApplicationParameterValue.Foo
  • 如果您在帖子中有正确的属性名称,它将适用于所有级别。尝试发布数据并分析表单数据。
  • 我已经方便地创建了示例。
  • 谢谢,我试试看!
【解决方案2】:

在得到有用的答案后,我能够让事情完全按照我想要的方式工作。我所做的是服务器端和客户端代码的组合,其想法基本上是在 ViewModel 中添加一个附加属性,我将其命名为 ControlName 并且是字符串类型。这样做的好处是,如果您的 ViewModel 发生更改,您可以轻松地将代码调整为当前需求而无需太多麻烦,更不用说您只需将 ControlName 属性添加到每个 ViewModel 子级别即可轻松进入多个深度级别。

注意:以下示例不是 OP 中提到的示例

首先,您需要某种包装器(在我的例子中是一个表格)和一个链接,它允许您创建新的控件行:

        @Html.ActionLink("Add attribute", "AddProductCategoryAttribute", null, new { id = "addProductCategoryAttribute" })
        <table class="table table-condensed table-striped">
            <thead>
                <tr>
                    <th>

                    </th>
                    <th>
                        Attribute
                    </th>
                    <th>
                        Measure
                    </th>
                </tr>
            </thead>
            <tbody id="productCategoryAttributes"></tbody>
        </table>

在客户端你需要这样的东西

    <script type="text/javascript">
    $("#addProductCategoryAttribute").click(function () {
        elementCount = $(".productCategoryAttribute").length;

        $.ajax({
            url: this.href + "?elementCount=" + elementCount,
            cache: false,
            success: function (html) {
                $("#productCategoryAttributes").append(html);
            }
        });
        return false;
    })
</script>

注意附加到链接的 elementCount - 这个查询字符串用于让 Action 方法知道有多少元素已经存在。说到 Action 方法,现在是这个样子。

    public ActionResult AddProductCategoryAttribute(int elementCount)
    {
        ProductCategoryOverview.ProductCategoryAttributeVM productCategoryAttributeVM = new ProductCategoryOverview.ProductCategoryAttributeVM();
        productCategoryAttributeVM.ControlName = "ChangeThisNameToWhateverIsNeeded[" + elementCount.ToString() + "].";
        productCategoryAttributeVM.Keep = true;

        return View(productCategoryAttributeVM);
    }

【讨论】:

    猜你喜欢
    • 2015-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-08
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多