MVC3 Html.BeginForm внутри столбца WebGrid? - PullRequest
5 голосов
/ 29 ноября 2011

Сегодня вечером у меня возникла несколько сумасшедшая идея, и я выполнил 3/4 пути к ее реализации и столкнулся со странной проблемой. Я хотел автоматически сгенерировать индекс всех методов на контроллере, чем вернуть ActionResult, а также простую форму для каждого из них, чтобы представить свои действительные данные. Выглядит как довольно простая вещь, которую можно сделать с помощью отражения:

Quickie 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>

Как видите, теги визуализируют за пределами таблицы!Есть идеи, что я здесь делаю не так?Или вы просто не можете делать BeginForm внутри веб-сетки?Есть ли какой-нибудь лучший подход для изготовления отдельных форм?

Заранее спасибо!

Ответы [ 2 ]

3 голосов
/ 29 ноября 2011

Попробуйте отрендерить <form> самостоятельно, без использования помощника.

Похоже, что лямбды выполняются внутри помощника, прежде чем он выплевывает содержимое, что приводит к немедленному выводу BeginForm.

2 голосов
/ 10 сентября 2012

Я не уверен, поможет ли это в вашем случае, но у меня была похожая проблема, и я сделал следующее:

  1. Создать частичное со следующим кодом

    @using(Html.BeginForm()){
        //some code
    }
    
  2. В месте, где возникла проблема, назовите это частичное, так что в вашем случае это будет что-то вроде:

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

PS: Место, где я позвонил, частично изменилось, поэтому я не уверен, сработает ли выше.

...