MVC3中如何在WebGrid列中使用Html.BeginForm?

5

今晚我有一个有点疯狂的想法,已经实现了3/4并遇到了奇怪的问题.. 我想自动生成控制器上所有返回ActionResult的方法的索引,以及每个方法的简单表单来提交有效数据.. 通过反射似乎很容易做到:

快速的ViewModel来保存每个反射的操作:

public class ReflectedAction
{
    public ReflectedAction(MethodInfo methodInfo, string controllerName)
    {
        this.ActionName = methodInfo.Name;
        this.ControllerName = controllerName;
        this.Parameters = methodInfo.GetParameters().Select(p => p.Name);
    }

    public string ControllerName { get; set; }

    public string ActionName { get; set; }

    public IEnumerable<string> Parameters { get; set; }
}

在当前控制器上反映所有操作的行动:

public virtual ActionResult AutoIndex()
{
    Type controllerType = this.ControllerContext.Controller.GetType();
    string controllerName = controllerType.Name.Replace("Controller", string.Empty);

    var methods = this.ControllerContext.Controller.GetType().GetMethods().Where(
            m => m.ReturnType.Name.Contains("ActionResult"));

    var model = methods.Select(m => new ReflectedAction(m, controllerName));

    return View(model);
}

在视图中,我只想使用一个简单的WebGrid来将每个操作呈现为一行,第一列是操作的名称,第二列是一个迷你表单,可以填写操作所具有的任何字段(我尝试将其作为帮助程序或内联在网格格式中,后者在此处包括):

@using TfsMvc.Controllers
@model IEnumerable<TestController.ReflectedAction>

@{
    ViewBag.Title = "AutoIndex";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>AutoIndex</h2>

@{
    var grid = new WebGrid(
        source: Model,
        ajaxUpdateContainerId: "grid",
        defaultSort: "ActionName",
        canPage: false);
}

<div id="grid">
    @grid.GetHtml(
    tableStyle: "grid",
    headerStyle: "head",
    alternatingRowStyle: "alt",
    columns: grid.Columns(
        grid.Column("ActionName"),
        grid.Column(format: (action) =>
            {
                using (Html.BeginForm((string)action.ActionName, (string)action.ControllerName, FormMethod.Get))
                {
                    string htmlString = string.Empty;

                    foreach (string parameter in action.Parameters)
                    {
                        htmlString = "<span>" + Html.Label(parameter) + Html.TextBox(parameter) + "</span>";
                    }

                    htmlString += "<input type=\"submit\" />";

                    return new HtmlString(htmlString);
                }
            }))
        )
</div>

网格看起来渲染正确,但奇怪的是所有的表单HTML标签都渲染在网格外面,而控件则渲染在网格里面:

<div id="grid">
    <form action="/Test/CloneTestPlan" method="get"></form>
    <form action="/Test/ConfigureTestPlan" method="get"></form>
    <form action="/Test/EnvConfig" method="get"></form>
    <form action="/Test/FixTestLink" method="get"></form>

    <!-- ton of other actions snipped-->

    <table class="grid">
        <thead>
            <tr class="head"><th scope="col"><a href="#" onclick="$(&#39;#grid&#39;).load(&#39;/Test/SecretIndex?sort=ActionName&amp;sortdir=DESC&amp;__=634581349851993336 #grid&#39;);">ActionName</a></th><th scope="col"></th></tr>
        </thead>
        <tbody>
            <tr><td>CloneTestPlan</td><td><span><label for="subid">subid</label><input id="subid" name="subid" type="text" value="" /></span><input type="submit" /></td></tr>
            <tr class="alt"><td>ConfigureTestPlan</td><td><span><label for="apply">apply</label><input id="apply" name="apply" type="text" value="" /></span><input type="submit" /></td></tr>
            <tr><td>EnvConfig</td><td><span><label for="create">create</label><input id="create" name="create" type="text" value="" /></span><input type="submit" /></td></tr>
            <tr class="alt"><td>FixTestLink</td><td><span><label for="commit">commit</label><input id="commit" name="commit" type="text" value="" /></span><input type="submit" /></td></tr>

            <!-- ton of other actions snipped-->

        </tbody></table>
</div>

如您所见,标签在表格之外呈现!我做错了什么?或者说Webgrid中不能使用BeginForm?有更好的方法来创建多个单独的表单吗?

谢谢!


这真的很有趣。你用它来向开发团队展示功能吗? - Brian White
抱歉回复晚了,没看到你添加了评论。实际上主要是我懒得手动制作静态索引。:) 我有很多操作,可能记不住它们的名称或需要的确切参数。它们通常都有合理的名称,所以我通常可以猜到...但是自动生成的索引显示它们所有更加清晰明了。 - superlime
2个回答

3
尝试不使用帮助程序自行呈现<form>
看起来,Lambda表达式在帮助程序内部执行,然后将内容输出,这导致BeginForm立即呈现到输出中。

啊哈!这至少可以解释这种奇怪的行为了!手动渲染<form>确实可以工作,但感觉很不好,并且意味着我还要担心手动正确地渲染路径。我真的很想以更清晰的方式完成这个任务...有没有办法强制助手程序在我期望的时间内在lambda中执行?如果不是这样,这似乎是MVC中的一个错误。 - superlime
你仍然可以使用UrlHelper来呈现URL。你也可以尝试调用Html.BeginFormHtml.EndForm而不使用using指令。或者自己编写扩展方法。 - Jakub Konecki

2

我不确定这对你有帮助,但我曾经遇到过类似的问题,我所做的是:

  1. Create partial with following code

    @using(Html.BeginForm()){
        //some code
    }
    
  2. In place where problem occurred, call this partial, so in your case it would be something like:

    grid.Column(format: (action) =>
    {
        Html.Partial("SomePartial")
    })
    

注意:我调用Partial的地方不同,因此我不确定上面的方法是否有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接