C# Asp MVC 4 创建类似于 Html.BeginForm 的自定义 html helper 方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14236017/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:07:27  来源:igfitidea点击:

Asp MVC 4 creating custom html helper method similar to Html.BeginForm

c#asp.net-mvc-3asp.net-mvc-4

提问by Mdb

I have the following html:

我有以下 html:

<div data-bind="stopBindings">

    <div data-viewId="languageList" data-bind="with: viewModel">
       <table>
              <tr>
                   <td ><label for="availableLanguages">Available Languages:</label></td>
              </tr>
       <table>
    </div>

</div>

I want to make a custom html helper and use it like this (similar to Html.BeginForm)

我想制作一个自定义的 html helper 并像这样使用它(类似于Html.BeginForm

@Html.BeginView()
{
    <table>
        <tr>
            <td ><label for="availableLanguages">Available Languages:</label></td>
        </tr>
    </table>
}

I started making my helper method

我开始制作我的辅助方法

public static class BeginViewHelper
    {
        public static MvcHtmlString BeginView(this HtmlHelper helper, string viewId)
        {

            var parentDiv = new TagBuilder("div");
            parentDiv.MergeAttribute("data-bind", "preventBinding: true");
            return new MvcHtmlString();
        }

    }

I read how to make basic html helper but the examples I saw does not give me information how to make it in my case. I am very new to asp mvc and every help will be greatly appreciated.

我阅读了如何制作基本的 html 帮助程序,但我看到的示例并没有为我提供如何在我的情况下制作它的信息。我对 asp mvc 很陌生,每一个帮助都将不胜感激。

UPDATE 2:

更新 2:

Obviously I am missing something. I am calling this in my view:

显然我错过了一些东西。在我看来,我称之为:

@Html.BeginView()
{
    <table>
        <tr>
            <td ><label >test</label></td>
        </tr>
    </table>
}

Everything seems fine it even has intellisense. But the output in the browser is the following:

一切似乎都很好,甚至还有智能感知。但是浏览器中的输出如下:

Omega.UI.WebMvc.Helpers.BeginViewHelper+MyView { 


test

 } 

This is my helper method:

这是我的辅助方法:

namespace Omega.UI.WebMvc.Helpers
{
    public static class BeginViewHelper
    {
        public static IDisposable BeginView(this HtmlHelper helper)
        {
            helper.ViewContext.Writer.Write("<div data-bind=\"preventBinding: true\">");
            helper.ViewContext.Writer.Write("<div data-viewId=\"test\">");

            return new MyView(helper);
        }

        class MyView : IDisposable
        {
            private HtmlHelper _helper;

            public MyView(HtmlHelper helper)
            {
                this._helper = helper;
            }

            public void Dispose()
            {
                this._helper.ViewContext.Writer.Write("</div>");
                this._helper.ViewContext.Writer.Write("</div>");
            }
        }
    }
}

and I have registered the namespace in ~/Views/web.config

我已经在 ~/Views/web.config 中注册了命名空间

 <add namespace="Omega.UI.WebMvc.Helpers" />

采纳答案by S?awomir Rosiek

You can't return MvcHtmlString. Instead of that you should write html to the writer and return class that implement IDisposable and during invoking Dispose will write closing part of your HTML.

你不能返回 MvcHtmlString。相反,您应该将 html 写入编写器并返回实现 IDisposable 的类,并且在调用 Dispose 期间将编写 HTML 的关闭部分。

public static class BeginViewHelper
{
    public static IDisposable BeginView(this HtmlHelper helper, string viewId)
    {
        helper.ViewContext.Writer.Write(string.Format("<div id='{0}'>", viewId));

        return new MyView(helper);
    }

    class MyView : IDisposable
    {
        private HtmlHelper helper;

        public MyView(HtmlHelper helper)
        {
            this.helper = helper;
        }

        public void Dispose()
        {
            this.helper.ViewContext.Writer.Write("</div>");
        }
    }
}

If you have more complex structure you can try to use TagBuilder:

如果您有更复杂的结构,您可以尝试使用 TagBuilder:

TagBuilder tb = new TagBuilder("div");
helper.ViewContext.Writer.Write(tb.ToString(TagRenderMode.StartTag));

回答by Felipe Oriani

The BeginFormmethod of asp.net mvc returns a IDisposableinstance of the MvcFormclass. If you look inside the asp.net mvc code on codeplex, you can check how the asp.net mvc team has developed this feature.

BeginFormasp.net mvc的方法返回类的一个IDisposable实例MvcForm。如果您查看codeplex 上asp.net mvc 代码,您可以查看 asp.net mvc 团队是如何开发此功能的。

Take a look at theses links:

看看这些链接:

MvcForm class (IDisposable) http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/8b17c2c49f88#src/System.Web.Mvc/Html/MvcForm.cs

MvcForm 类(IDisposable) http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/8b17c2c49f88#src/System.Web.Mvc/Html/MvcForm.cs

Forms Extensions (for html helper) http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/8b17c2c49f88#src/System.Web.Mvc/Html/FormExtensions.cs

表单扩展(用于 html 助手) http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/8b17c2c49f88#src/System.Web.Mvc/Html/FormExtensions.cs

回答by Brad Christie

Slawekhas the correct answer, but I thought I would add to it with my experience.

Slawek正确的答案,但我想我会用我的经验补充它。

I wanted to create a helper to display widgets on a page (almost like jQuery's widgets with the title bar and a content portion). Something to the effect of:

我想创建一个助手来在页面上显示小部件(几乎就像带有标题栏和内容部分的 jQuery 小部件)。有以下作用:

@using (Html.BeginWidget("Widget Title", 3 /* columnWidth */))
{
    @* Widget Contents *@
}

The MVC source uses something similar to what Slawek posted, but I feel like placing the start tag in the helper and end tag in the actual object wasn't "tidy", nor did it keep concerns in the corect place. Should I want to change the appearance, I'm now doing so in two places instead of what I felt was one logical place. So I came up with the following:

MVC 源代码使用类似于 Slawek 发布的内容,但我觉得将开始标记放在帮助程序中并将结束标记放在实际对象中并不“整洁”,也没有在正确的地方保留关注点。如果我想改变外观,我现在在两个地方这样做,而不是我认为是一个合乎逻辑的地方。所以我想出了以下内容:

/// <summary>
/// Widget container
/// </summary>
/// <remarks>
/// We make it IDIsposable so we can use it like Html.BeginForm and when the @using(){} block has ended,
/// the end of the widget's content is output.
/// </remarks>
public class HtmlWidget : IDisposable
{
    #region CTor

    // store some references for ease of use
    private readonly ViewContext viewContext;
    private readonly System.IO.TextWriter textWriter;

    /// <summary>
    /// Initialize the box by passing it the view context (so we can
    /// reference the stream writer) Then call the BeginWidget method
    /// to begin the output of the widget
    /// </summary>
    /// <param name="viewContext">Reference to the viewcontext</param>
    /// <param name="title">Title of the widget</param>
    /// <param name="columnWidth">Width of the widget (column layout)</param>
    public HtmlWidget(ViewContext viewContext, String title, Int32 columnWidth = 6)
    {
        if (viewContext == null)
            throw new ArgumentNullException("viewContext");
        if (String.IsNullOrWhiteSpace(title))
            throw new ArgumentNullException("title");
        if (columnWidth < 1 || columnWidth > 12)
            throw new ArgumentOutOfRangeException("columnWidth", "Value must be from 1-12");

        this.viewContext = viewContext;
        this.textWriter = this.viewContext.Writer;

        this.BeginWidget(title, columnWidth);
    }

    #endregion

    #region Widget rendering

    /// <summary>
    /// Outputs the opening HTML for the widget
    /// </summary>
    /// <param name="title">Title of the widget</param>
    /// <param name="columnWidth">Widget width (columns layout)</param>
    protected virtual void BeginWidget(String title, Int32 columnWidth)
    {
        title = HttpUtility.HtmlDecode(title);

        var html = new System.Text.StringBuilder();

        html.AppendFormat("<div class=\"box grid_{0}\">", columnWidth).AppendLine();
        html.AppendFormat("<div class=\"box-head\">{0}</div>", title).AppendLine();
        html.Append("<div class=\"box-content\">").AppendLine();

        this.textWriter.WriteLine(html.ToString());
    }

    /// <summary>
    /// Outputs the closing HTML for the widget
    /// </summary>
    protected virtual void EndWidget()
    {
        this.textWriter.WriteLine("</div></div>");
    }

    #endregion

    #region IDisposable

    private Boolean isDisposed;

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    public virtual void Dispose(Boolean disposing)
    {
        if (!this.isDisposed)
        {
            this.isDisposed = true;
            this.EndWidget();
            this.textWriter.Flush();
        }
    }

    #endregion
}

Then, that makes our helper a little more clear (and no UI code in two places):

然后,这使我们的助手更加清晰(并且两个地方没有 UI 代码):

public static HtmlWidget BeginWidget(this HtmlHelper htmlHelper, String title, Int32 columnWidth = 12)
{
  return new HtmlWidget(htmlHelper.ViewContext, title, columnWidth);
}

Then we can use it as I've done at the top of this post.

然后我们可以像我在这篇文章的顶部所做的那样使用它。