ASP.NET MVC使用Bootstrap系列(5)——创建ASP.NET MVC Bootstrap Helpers
阅读目录
序言
ASP.NET MVC允许开发者创建自定义的HTML Helpers,不管是使用静态方法还是扩展方法。一个HTML Helper本质上其实是输出一段HTML字符串。
HTML Helpers能让我们在多个页面上公用同一段HTML标记,这样不仅提高了稳定性也便于开发者去维护。当然对于这些可重用的代码,开发者也方便对他们进行单元测试。所以,创建ASP.NET MVC Bootstrap Helpers是及其有必要的。
内置的HTML Helpers
ASP.NET MVC内置了若干标准HTML Helpers,通过@HTML来调用这些方法在视图引擎中解析、渲染输出HTML内容,这允许开发者在多个视图中重用公共的方法。
举个栗子,以下代码产生一个type等于text的Input ,并且其id和name都等于CustomerName,其Value等于Northwind Traders:
- @Html.TextBox("CustomerName","Northwind Traders");
大多数内置的HTML helpers提供传入匿名类型为元素产生指定HTML属性的选项,对上述的@HTML.TextBox方法稍作修改,通过传入匿名类型设置输出元素的style属性:
- @Html.TextBox("CustomerName","Northwind Traders", new { style="" })
创建自定义的Helpers
因为Bootstrap提供了大量不同的组件,所以创建Bootstrap helpers可以在多个视图上快速使用这些组件。在ASP.NET MVC中最简单创建Bootstrap helpers是通过@helper语法来实现。一个自定义的helper可以包含任何HTML标记甚至Razor标记,你可以通过如下步骤来创建:
- 在项目的根目录创建文件夹App_Code
- 在App_Code文件夹中新建BootstrapHelpers.cshtml文件并加入如下代码
- @helper PrimaryButtonSmall(string id,string caption)
- {
- <button id="@id" type="button" class="btn btn-primary btn-sm">@caption</button>
- }
上述代码使用@helper创建了一个新的名为PrimaryButtonSmall helper,它接受2个参数,分别是Id和caption。其中,它产生一个Button类型的HTML标记并设置了Bootstrap的样式。
注意:任何自定义的helpers必须存在App_Code文件夹中,这样才能被ASP.NET MVC视图识别。
- 在视图中通过 @BootstrapHelpers.PrimaryButtonSmall("btnSave","保存")来使用新创建的helper。
- 它将产生如下Bootstrap HTML元素:
当然,为了让我们的helper更加通用性,比如指定大小、样式等,对上述稍作如下修改,增加传入的参数:
- @helper Button(string style, string size, string caption, string id)
- {
- <button id="@id" type="button" class="btn btn-@style btn-@size">@caption </button>
- }
现在我们可以这样去使用:
- @BootstrapHelpers.Button("danger","lg","危险","btnDanger")
它将产生如下样式的按钮:
不过,这种方式的helper唯一的不足是你需要"hard code"传入样式和尺寸,这可能需要你非常熟悉Bootstrap的样式。
使用静态方法创建Helpers
通过静态方法同样也能快速方便的创建自定义Bootstrap helpers,同样它也是返回了HTML标记,要创建静态方法,你可以按照如下步骤来实现:
- 添加命了Helpers的文件夹
- 创建如下枚举类
- public class ButtonHelper
- {
- public static MvcHtmlString Button(string caption, Enums.ButtonStyle style, Enums.ButtonSize size)
- {
- if (size != Enums.ButtonSize.Normal)
- {
- return new MvcHtmlString(string.Format("<button type=\"button\" class=\"btn btn-{0} btn-{1}\">{2}</button>", style.ToString().ToLower(), ToBootstrapSize(size), caption));
- }
- return new MvcHtmlString(string.Format("<button type=\"button\" class=\"btn btn-{0}\">{1}</button>", style.ToString().ToLower(), caption));
- }
- private static string ToBootstrapSize(Enums.ButtonSize size)
- {
- string bootstrapSize = string.Empty;
- switch (size)
- {
- case Enums.ButtonSize.Large:
- bootstrapSize = "lg";
- break;
- case Enums.ButtonSize.Small:
- bootstrapSize = "sm";
- break;
- case Enums.ButtonSize.ExtraSmall:
- bootstrapSize = "xs";
- break;
- }
- return bootstrapSize;
- }
- }
Button方法返回了一个MvcHtmlString对象,它代表了编码过后的HTML字符。
- 通过使用静态方法来调用:
- @ButtonHelper.Button("危险", Enums.ButtonStyle.Danger, Enums.ButtonSize.Large)
你可以和之前的"hard code"写法进行比较,尽管他们产生相同的结果:
- @BootstrapHelpers.Button("danger","lg","危险","btnDanger")
使用扩展方法创建Helpers
内置的ASP.NET MVC helper(@HTML)是基于扩展方法的,我们可以再对上述的静态方法进行升级——使用扩展方法来创建Bootstrap helpers。
- 在Helpers文件夹下创建ButtonExtensions类
- 修改ButtonExtensions为Static类型
- 修改Namespace为System.Web.Mvc.Html,这样方便@HTML调用扩展方法
- 添加扩展方法,返回MvcHtmlString
- public static MvcHtmlString BootstrapButton(this HtmlHelper helper, string caption, Enums.ButtonStyle style, Enums.ButtonSize size)
- {
- if (size != Enums.ButtonSize.Normal)
- {
- return new MvcHtmlString(string.Format("<button type=\"button\" class=\"btn btn-{0} btn-{1}\">{2}</button>", style.ToString().ToLower(), ToBootstrapSize(size), caption));
- }
- return new MvcHtmlString(string.Format("<button type=\"button\" class=\"btn btn-{0}\">{1}</button>", style.ToString().ToLower(), caption));
- }
因为BootstrapButton方法是扩展方法,通过如下方式去调用:
- @Html.BootstrapButton("很危险",Enums.ButtonStyle.Danger,Enums.ButtonSize.Large)
写法虽不同,但返回的结果都是一致的。
创建Fluent Helpers
Fluent Interface(参考:http://martinfowler.com/bliki/FluentInterface.html)用于软件开发实现了一种面向对象的API,以这种方式,它提供了更多的可读性代码,易于开发人员理解。通常通过链式编程来实现。
举个栗子,我们将创建一个HTML helper来产生一个可关闭的警告框,使用Fluent Interface可以这样来调用:
- @Html.Alert("警告").Warning().Dismissible()
所以要创建Fluent helpers,需要实现如下步骤:
- 创建IFluentAlert实现IHtmlString接口,这是非常重要的一步,对于ASP.NET MVC Razor视图引擎,如果@之后返回的类型实现了IHtmlString接口,那么视图引擎会自动调用ToHtmlString()方法,返回实际的HTML标记。
- public interface IAlertFluent : IHtmlString
- {
- IAlertFluent Dismissible(bool canDismiss = true);
- }
- 创建IAlert实现IFluentAlert接口
- public interface IAlert : IAlertFluent
- {
- IAlertFluent Danger();
- IAlertFluent Info();
- IAlertFluent Success();
- IAlertFluent Warning();
- }
- 创建Alert继承IAlert接口
- public class Alert : IAlert
- {
- private Enums.AlertStyle _style;
- private bool _dismissible;
- private string _message;
- public Alert(string message)
- {
- _message = message;
- }
- public IAlertFluent Danger()
- {
- _style = Enums.AlertStyle.Danger;
- return new AlertFluent(this);
- }
- public IAlertFluent Info()
- {
- _style = Enums.AlertStyle.Info;
- return new AlertFluent(this);
- }
- public IAlertFluent Success()
- {
- _style = Enums.AlertStyle.Success;
- return new AlertFluent(this);
- }
- public IAlertFluent Warning()
- {
- _style = Enums.AlertStyle.Warning;
- return new AlertFluent(this);
- }
- public IAlertFluent Dismissible(bool canDismiss = true)
- {
- this._dismissible = canDismiss;
- return new AlertFluent(this);
- }
- public string ToHtmlString()
- {
- var alertDiv = new TagBuilder("div");
- alertDiv.AddCssClass("alert");
- alertDiv.AddCssClass("alert-" + _style.ToString().ToLower());
- alertDiv.InnerHtml = _message;
- if (_dismissible)
- {
- alertDiv.AddCssClass("alert-dismissable");
- alertDiv.InnerHtml += AddCloseButton();
- }
- return alertDiv.ToString();
- }
- private static TagBuilder AddCloseButton()
- {
- var closeButton = new TagBuilder("button");
- closeButton.AddCssClass("close");
- closeButton.Attributes.Add("data-dismiss", "alert");
- closeButton.InnerHtml = "×";
- return closeButton;
- }
- }
上述代码中,通过TagBuilder可以快速的创建HTML元素。
- 创建AlertFluent继承IAlertFluent
- public class AlertFluent : IAlertFluent
- {
- private readonly Alert _parent;
- public AlertFluent(Alert parent)
- {
- _parent = parent;
- }
- public IAlertFluent Dismissible(bool canDismiss = true)
- {
- return _parent.Dismissible(canDismiss);
- }
- public string ToHtmlString()
- {
- return _parent.ToHtmlString();
- }
- }
- 最后创建静态方法
- public static class AlertHelper
- {
- public static Alert Alert(this HtmlHelper html,string message)
- {
- return new Alert(message);
- }
- }
通过构建这种Fluent API,我们可以链式的去创建Bootstrap 组件,这对于不熟悉Bootstrap Framework的人来说是非常方便的,我们可以使用@HTML.Alert("Title").Danger().Dismissible()来创建如下风格的警告框:
创建自动闭合的Helpers
在ASP.NET MVC中,内置的@HTML.BeginForm() helper就是一个自动闭合的helper。当然我们也能自定义自动闭合的helpers,只要实现IDisposable接口即可。使用IDisposable接口,当对象Dispose时我们输出元素的闭合标记,具体按照如下步骤:
- 所以在Helpers文件夹下创建一个名为Panel的文件夹
- 添加Panel,并实现IDisposable接口
- public class Panel : IDisposable
- {
- private readonly TextWriter _writer;
- public Panel(HtmlHelper helper, string title, Enums.PanelStyle style = Enums.PanelStyle.Default)
- {
- _writer = helper.ViewContext.Writer;
- var panelDiv = new TagBuilder("div");
- panelDiv.AddCssClass("panel-" + style.ToString().ToLower());
- panelDiv.AddCssClass("panel");
- var panelHeadingDiv = new TagBuilder("div");
- panelHeadingDiv.AddCssClass("panel-heading");
- var heading3Div = new TagBuilder("h3");
- heading3Div.AddCssClass("panel-title");
- heading3Div.SetInnerText(title);
- var panelBodyDiv = new TagBuilder("div");
- panelBodyDiv.AddCssClass("panel-body");
- panelHeadingDiv.InnerHtml = heading3Div.ToString();
- string html = string.Format("{0}{1}{2}", panelDiv.ToString(TagRenderMode.StartTag), panelHeadingDiv, panelBodyDiv.ToString(TagRenderMode.StartTag));
- _writer.Write(html);
- }
- public void Dispose()
- {
- _writer.Write("</div></div>");
- }
- }
上述代码中利用Write属性可以在当前视图中输出HTML标记,并在Dispose方法里输出2个闭合的<div>标签。
注意,我们重写了TagBuilder的ToString()方法,只让它生成<div>元素的开始标签。
- 在View中使用自动闭合的helpers
- @using (Html.Panel("Title", Enums.PanelStyle.Success))
- {
- <p>这是自动闭合的Helpers</p>
- <p>panel..</p>
- }
产生的结果如下:
小结
在这篇博客中,为了减少书写HTML标记,我们创建了若干Bootstrap helpers来实现。这些helpers的意义在于能让不了解Bootstrap Framework的人也能快速上手Bootstrap。
ASP.NET MVC使用Bootstrap系列(5)——创建ASP.NET MVC Bootstrap Helpers的更多相关文章
- 探索 ASP.Net Core 3.0系列三:ASP.Net Core 3.0中的Service provider validation
前言:在本文中,我将描述ASP.NET Core 3.0中新的“validate on build”功能. 这可以用来检测您的DI service provider是否配置错误. 具体而言,该功能可检 ...
- 探索ASP.Net Core 3.0系列六:ASP.NET Core 3.0新特性启动信息中的结构化日志
前言:在本文中,我将聊聊在ASP.NET Core 3.0中细小的变化——启动时记录消息的方式进行小的更改. 现在,ASP.NET Core不再将消息直接记录到控制台,而是正确使用了logging 基 ...
- ASP.NET MVC使用Bootstrap系列(1)——开始使用Bootstrap
阅读目录 Bootstrap结构介绍 在ASP.NET MVC 项目中添加Bootstrap文件 为网站创建Layout布局页 使用捆绑打包和压缩来提升网站性能 在Bootstrap项目中使用捆绑打包 ...
- 《ASP.NET Core In Action》读书笔记系列四 创建ASP.NET Core 应用步骤及相应CLI命令
一般情况下,我们都是从一个模板(template)开始创建应用的(模板:提供构建应用程序所需的基本代码).本节使用 Visual Studio 2017 .ASP.NET Core2.0和 Visua ...
- ASP.NET Web API实践系列06, 在ASP.NET MVC 4 基础上增加使用ASP.NET WEB API
本篇尝试在现有的ASP.NET MVC 4 项目上增加使用ASP.NET Web API. 新建项目,选择"ASP.NET MVC 4 Web应用程序". 选择"基本&q ...
- 学习ASP.NET Core Razor 编程系列三——创建数据表及创建项目基本页面
一.创建脚本工具并执行初始迁移 在本节中,您将使用包管理控制台(PMC)来更新数据库: •添加VisualStudio Web代码生成包.这个包是运行脚本引擎所必需的. • 执行Add-Migrati ...
- ASP.NET Web API实践系列01,以ASP.NET Web Form方式寄宿
创建一个空的ASP.NET Web Form项目. 右键项目,添加新项,创建Web API控制器类,TestController. 删除掉TestController默认的内容,编写如下: using ...
- C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理
C#编译器优化那点事 使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的.优化代码 ...
- 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- C#中的函数式编程:递归与纯函数(二) 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面
C#中的函数式编程:递归与纯函数(二) 在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential ...
随机推荐
- 资源: CustomResource, ResourceDictionary, 加载外部的 ResourceDictionary 文件
CustomResource ResourceDictionary 加载外部的 ResourceDictionary 文件 示例1.演示“CustomResource”相关知识点Resource/Cu ...
- slim
Slim 是一个非常优雅的 PHP 微框架,非常适合做API,支持多种http请求方式,比如get,post,delete,put等 安装使用Composer composer require sli ...
- Java套接字
前言: 本文补充一下Java关于套接字方面的内容,因为其应用相对比较简单,所以下面介绍两个程序实例. ------------------------------------------------- ...
- C++强制类型转换操作符 const_cast
const_cast也是一个强制类型转换操作符.<C++ Primer>中是这样描述它的: 1.将转换掉表达式的const性质. 2.只有使用const_cast才能将const性质性质转 ...
- if __name__ == '__main__':
python if __name__ == '__main__': 模块是对象,并且所有的模块都有一个内置属性 __name__.一个模块的 __name__ 的值取决于您如何应用模块.如果 impo ...
- SQL怎么输出前n个记录? n是中间计算得到的,不支持变量传递
需求: 表 people_crowed_test 按view_num排序后,输出该表的记录前30%的aid, buyer_id; 需求场景下的诸多限制: 1) 不支持变量赋值,也就是无法把中间结果保存 ...
- 【BZOJ-2725】故乡的梦 Dijsktra + Tarjan + Dinic + BFS + 堆
2725: [Violet 6]故乡的梦 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 502 Solved: 173[Submit][Status ...
- 【PowerOJ1739】 魔术球问题
https://www.oj.swust.edu.cn/problem/show/1739 (题目链接) 题意 n个柱子上放小球,每根柱子上相邻两个小球的数字之和必须是完全平方数,只有放了x号小球才可 ...
- NOIP2014
DAY1 生活大爆炸版石头剪刀布 直接模拟即可. // codevs3716 #include<algorithm> #include<iostream> #include&l ...
- 【codevs1086】 栈
http://codevs.cn/problem/1086/ (题目链接) 题意 给出1~n总共n个数,对它们进行入栈出栈操作,问一共有多少种不同的方案. Solution 找规律手玩前5个1 2 5 ...