如何在 ASP.NET MVC 中创建可重复使用的自定义 HTML 面板?

How can I create a re-usable custom HTML panel in ASP.NET MVC?

我正在尝试在 ASP.NET MVC 中创建一个可重复使用的 UI 元素,它环绕着我选择放置在其中的任何内容。我的第一个想法是创建一个局部视图,但这似乎对我想要完成的事情没有帮助。

模板

例如,我想创建一些与此类似的可重用标记(请原谅伪代码):

<div class="panel panel-default">
  <div class="panel-body">
    @RenderBody()
  </div>
</div>

一个简单的例子

那么在我看来我想做类似这样的事情:

@Render.Partial("MyPanel")
{
    <img src="image.jpg" />
}

假设代码按预期工作,它将生成以下内容:

<div class="panel panel-default">
  <div class="panel-body">
     <img src="image.jpg" />
  </div>
</div>

另一个示例,带有更复杂的标记

从理论上讲,我希望能够将我想要的任何内容放置在其中一个面板中。因此,即使是更复杂的标记仍然清晰可见。

@Render.Partial("MyPanel")
{
    <form>
      <div class="form-group">
        <label for="exampleInputEmail1">Email address</label>
        <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
      </div>
      <div class="form-group">
        <label for="exampleInputPassword1">Password</label>
        <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
      </div>
      <div class="form-group">
        <label for="exampleInputFile">File input</label>
        <input type="file" id="exampleInputFile">
        <p class="help-block">Example block-level help text here.</p>
      </div>
      <div class="checkbox">
        <label>
          <input type="checkbox"> Check me out
        </label>
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
    </form>
}

就像第一个示例一样,它会将所有内容包装在我的模板的页眉和页脚中:

<div class="panel panel-default">
  <div class="panel-body">
    <form>
      <div class="form-group">
        <label for="exampleInputEmail1">Email address</label>
        <input type="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
      </div>
      .. truncated ..
      <button type="submit" class="btn btn-default">Submit</button>
    </form>
  </div>
</div>

已知的可能性

我能够通过创建自定义控件在 ASP.NET WebForms 中做到这一点。这似乎在 MVC 中也应该是直截了当的事情,但我还没有完全能够找到一个好的解决方案。

在 MVC 中创建可重用内容的方法有很多,但它们各有利弊。例如,自定义 Html 帮助程序是一种常用方法,但它们需要编写的代码比您可能想要的要多得多。

您当然可以使用分部视图,只需将包含您要呈现的内容的模型传递给分部...但这也可能有点令人困惑。

我想您正在寻找的可能是 Razor Helpers。这些在此处有更详细的解释:

http://weblogs.asp.net/scottgu/asp-net-mvc-3-and-the-helper-syntax-within-razor

但是,基本结构如下所示:

@helper MyHelper(string content)
{
     <div class="panel panel-default">
         <div class="panel-body">
             @Html.Raw(content)
         </div>
     </div>
}

然后你这样使用它:

@MyHelper("<img src="image.jpg" />")

你不必使用字符串,你可以使用结构化内容、模型等。你可以在里面使用其他帮助器。您可以按照本文后面的描述重新使用它们。

但是,您可能想要开始考虑将您的页面更多地以数据为中心。如果您使用 EditorTemplates 呈现您的数据,那么您将根据您的数据类型呈现控件,而不是呈现您的页面并尝试调整您的页面以包含您的数据。

您可以使用 "DynamicInvoke" 创建带有动态标记的 html 助手,例如:

public static IHtmlString CustomPanel(this HtmlHelper htmlHelper, Func<object, object> panelMarkup = null)
{
    return CustomPanel(htmlHelper, (panelMarkup == null ? "" : panelMarkup.DynamicInvoke(htmlHelper.ViewContext).ToString()));
}

public static IHtmlString CustomPanel(this HtmlHelper htmlHelper, string content)
{
    TagBuilder div = new TagBuilder("div");
    div.AddCssClass("panel panel-default");

    TagBuilder innerDiv = new TagBuilder("div");
    innerDiv.AddCssClass("panel-body");

    innerDiv.InnerHtml = content;
    div.InnerHtml = innerDiv.ToString();

    return new HtmlString(div.ToString());
}

然后你会像这样使用它:

@Html.CustomPanel(
    @<text>
        <div>My Custom Markup</div>
        <span>More Stuff</span>
    </text>
)

您的最终内容将如下所示:

<div class="panel panel-default">
    <div class="panel-body">
        <div>My Custom Markup</div>
        <span>More Stuff</span>
    </div>
</div>

你看到这个在一些第 3 方小部件库中经常使用(kendo-ui 是我所知道的主要的)