【问题标题】:Asp MVC 4 creating custom html helper method similar to Html.BeginFormAsp MVC 4 创建类似于 Html.BeginForm 的自定义 html 帮助器方法
【发布时间】:2014-10-07 04:37:20
【问题描述】:

我有以下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>

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

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

我开始制作我的辅助方法

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();
        }

    }

我阅读了如何制作基本的 html 助手,但我看到的示例并没有告诉我如何在我的情况下制作它。我对 asp mvc 很陌生,我们将不胜感激。

更新 2:

显然我错过了一些东西。在我看来,我这样称呼:

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

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

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


test

 } 

这是我的辅助方法:

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>");
            }
        }
    }
}

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

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

【问题讨论】:

    标签: c# asp.net-mvc-3 asp.net-mvc-4


    【解决方案1】:

    您不能返回 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>");
            }
        }
    }
    

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

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

    【讨论】:

    • 我按照您的代码进行了实现,但结果并不如预期。你能看看我的帖子吗?我又更新了。
    • 使用using (Html.BeginView()) 而不是@Html.BeginView()
    • 这行得通。你知道为什么它不按我的方式工作吗?两种方式不相等吗?
    • 标志@导致该方法的剃刀渲染结果。如果您的方法返回字符串或 MvcHtmlString,则将其写入 Writer。如果您的方法返回 MyView 然后剃刀在 MyView 上调用 ToString。
    【解决方案2】:

    Slawekcorrect answer,但我想我会根据我的经验添加它。

    我想创建一个帮助器来在页面上显示小部件(几乎就像 jQuery 的带有标题栏和内容部分的小部件)。大意是:

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

    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
    }
    

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

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

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

    【讨论】:

      【解决方案3】:

      asp.net mvc 的BeginForm 方法返回MvcForm 类的IDisposable 实例。如果您查看asp.net mvc code on codeplex 内部,您可以查看asp.net mvc 团队是如何开发此功能的。

      看看这些链接:

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

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

      【讨论】:

        猜你喜欢
        • 2017-09-28
        • 2014-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-18
        • 2011-04-06
        • 1970-01-01
        • 2023-03-13
        相关资源
        最近更新 更多