随笔 - 165, 文章 - 0, 评论 - 18, 阅读 - 22万
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

自定义ASP.NET MVC Html标签辅助方法

Posted on   火冰·瓶  阅读(416)  评论(0编辑  收藏  举报

原文:https://blog.csdn.net/a497785609/article/details/50184779

 

在ASP.NET MVC中,Html辅助方法给我们程序员带来很多方便,其重要性也就不言自明。有时候,我们不想重复地写一些HTML代码,或者MS没有提供我们想要的那个HTML标签的Html辅助方法,那么,我们就可以通过自己定义一个Html扩展方法来达到这个目的。

比如,到目前为止,Html扩展方法中没有关于<input type="file" />这类标签的辅助方法,那么我们就可以自已实现一个。本文以实现<input type="file" />标签为例,演示如何实现自定义Html扩展方法。

 

一、实现自定义弱类型Html扩展方法

其实实现自定义Html扩展方法并不难,有兴趣的同学可以去看下MVC源代码,关于Html扩展方法部分。要用到System.Web.Mvc命名空间下的TagBuilder类,MvcHtmlString类。TagBuilder类为Html辅助方法生成HTML标签,MvcHtmlString代表HTML编码的字符串。扩展方法代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static class MyInputExtensions
{
    public static MvcHtmlString Input(this HtmlHelper htmlHelper, string name)
    {
 
        TagBuilder tagBuilder = new TagBuilder("input");//设置标签类型为input
 
        tagBuilder.Attributes.Add("type", "file");//为标签添加type属性及值
 
        tagBuilder.Attributes.Add("name", name);//为标签添加name属性及值
 
        tagBuilder.GenerateId(name);//为标签生成Id,name参数代码Id的值
 
        //创建经过HTML加密的字符串
 
        //TagRenderMode.SelfClosing枚举值代表当前标签是自动关闭的
 
        return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.SelfClosing));
    }
}

  

需要特别提醒的是,扩展方法类所在的命名空间最好设置为System.Web.Mvc,这样,我们在View中可以通过智能感知轻易找到,也不容易出错或者无法通过VS智能感知找到我们自定义的Html辅助方法,可以为我们省去很多不必要的麻烦。将上面代码编译,我们即可在View中通过智能感知看到我们自定义的Html辅助方法。如下图所示:

使用方法和其它Html辅助方法一样,如下代码所示:

      <%: Html.Input("Path") %> //字符串参数Path代表生成标签的name属性和id属性的值 

需要说明的是,本例所示是为了生成<input type="file">标签,是不用设置值的,读者可以通过自身情况定义扩展方法。然后运行,通过浏览器查看HTML源代码,如下图所示:

二、实现自定义强类型Html辅助方法

强类型辅助方法的一个好处是,我们可以通过编译器为我们检测一些错误,为我们节省一些排错的时间与精力。所以,强类型Html辅助方法是不可缺少的。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static class MyInputExtensions
 
{
 
    public static MvcHtmlString Input<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression)
 
    {
 
        string modelName = ExpressionHelper.GetExpressionText(expression);//从Lambda表达式中获取模型对应属性的名称
 
         TagBuilder tagBuilder = new TagBuilder("input");//设置标签类型为input
 
        tagBuilder.Attributes.Add("type", "file");//为标签添加type属性及值
 
         tagBuilder.Attributes.Add("name", modelName);//为标签添加name属性及值
 
         tagBuilder.GenerateId(modelName);//为标签生成Id,name参数代码Id的值
 
         //创建经过HTML加密的字符串
 
         //TagRenderMode.SelfClosing枚举值代表当前标签是自动关闭的
 
        return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.SelfClosing));
 
    }
 
}

  

然后我们编译,在View中,我们就可以通过智能感知看到我们新扩展的强类型Html辅助方法了。如下图所示:

  

我们可以通过如下代码使用新扩展的Html辅助方法:

       <%: Html.Input(model => model.Path) %>//Path代表model的Path属性,生成标签的name和id的属性值均会是Path

运行,我们通过浏览器查看生成的Html源代码如下图所示:

  

三、为标签错误输入添加CSS支持

对于要求输入的标签,如Text,如果用户输入错误内容,我们可以为当前标签添加CSS错误提示,为用户提供一个更加友好、人性化的界面。代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ModelState modelState;
 
if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState))
 
{
 
    if (modelState.Errors.Count > 0)
 
    {
 
        //添加错误提示CSS
 
         tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
 
     }
 
 }

  

将以上代码复制到我们自定义的扩展方法的返回MvcHtmlString字符串之前即可。

四、总结

本文通过演示如果实现自定义<input type="file" />标签的Html辅助方法,展示了如何在ASP.NET MVC中实现自定义Html辅助方法。对于ASP.NET MVC程序员来说,这是非常实用的。

 

五、补充

一个完整的扩展示例方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public static MvcHtmlString InputText<TModel, TValue>(this HtmlHelper<TModel> html,
            Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
        
            TagBuilder tagBuilder = new TagBuilder("input");
 
            var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
 
            //第1步:获取模型字段的显示文本
            string text = metadata.DisplayName ?? metadata.PropertyName;
 
            //第2步:获取模型字段的字段名
            var name = ExpressionHelper.GetExpressionText(expression);
 
            //第3步:获取模型字段的值
            #region 模型字段的值
 
            string value;
            ModelState modelState;
            string fullName = html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
            if (html.ViewData.ModelState.TryGetValue(fullName, out modelState) && modelState.Errors.Count > 0)
            {
                tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
            }
            if (modelState != null && modelState.Value != null)
            {
                value = modelState.Value.AttemptedValue;
            }
            else if (metadata.Model != null)
            {
                value = metadata.Model.ToString();
            }
            else
            {
                value = String.Empty;
            }
 
            #endregion
 
            tagBuilder.Attributes.Add("type", "text");
            tagBuilder.Attributes.Add("name", name);
            tagBuilder.Attributes.Add("value", value);
            //第4步:填充其他自定义属性
            tagBuilder.MergeAttributes(htmlAttributes, true);
            tagBuilder.GenerateId(name);
 
            return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.SelfClosing));
        }

  

另外一个例子

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
public static class FileUploadExtension
{
 
    private const string CanReadExts = ".doc;.docx;.rtf;.xml;.html;.htm;.odt;.xls;.xlsx;.ppt;.pptx;.pdf;.txt;.mpp";
    private const string ImgExts = ".jpg;.jpeg;.png;.bmp;.gif";
    private const string CanEditExts = ".doc;.docx";
 
    /// <summary>
    /// 上传文件扩展,绑定到模型字段
    /// </summary>
    /// <typeparam name="TModel">模型</typeparam>
    /// <typeparam name="TProperty">模型对应属性</typeparam>
    /// <param name="helper"></param>
    /// <param name="pathsExpr">保存上传文件路径的属性表达式</param>
    /// <param name="multi">是否多文件上传(false时为单文件)</param>
    /// <param name="fileTypeExts">上传文件扩展名,用“分号”分割不同扩展名(如: '.jpg','.png')</param>
    /// <param name="htmlAttributes">html属性集合对象</param>
    /// <param name="editMode">是否为编辑模式</param>
    /// <param name="onlineView">是否可以在线阅读</param>
    /// <param name="onlineEdit">是否可以在线编辑</param>
    /// <param name="callBack">上传成功的回掉函数</param>
    /// <returns></returns>
    public static MvcHtmlString FileUploadFor<TModel, TProperty>
        (this HtmlHelper<TModel> helper,
        Expression<Func<TModel, TProperty>> pathsExpr,
        bool multi = true,
        string fileTypeExts = null,
        object htmlAttributes = null,
        bool editMode = true,
        bool onlineView = true,
        bool onlineEdit = false, string callBack = "")
    {
        //检查model是否存在
        if (helper.ViewData != null && null == helper.ViewData.Model)
            throw new NoNullAllowedException("View Model 不能为空! 请确保 View Model 被创建了并且传输到当前视图.");
 
        //从model中获得数据
        if (helper.ViewData != null)
        {
            var model = helper.ViewData.Model;
 
            //检查是否绑定到了model的属性上
            var name = ExpressionHelper.GetExpressionText(pathsExpr);
            if (String.IsNullOrEmpty(name))
                throw new ArgumentException("名称不能为空!", "pathsExpr");
 
            //获得已经上传文件名称列表
            var pathsFunc = pathsExpr.Compile();
            var nameStr = "";
            if (pathsFunc(model) != null)
            {
                nameStr = pathsFunc(model).ToString();
            }
 
            var metadata = ModelMetadata.FromLambdaExpression(pathsExpr, helper.ViewData);
            var isRequired = metadata.IsRequired;
            var displayName = isRequired ? metadata.DisplayName : "";
 
            return FileUpload(helper, name, nameStr, multi, fileTypeExts, htmlAttributes, editMode, onlineView,
                onlineEdit, isRequired, displayName, callBack);
        }
        else
        {
            return new MvcHtmlString("");
        }
    }
 
    /// <summary>
    /// 上传文件,指定name和value不需要绑定到字段
    /// </summary>
    /// <param name="helper">上下文</param>
    /// <param name="name">后台接收时使用的名称</param>
    /// <param name="value">值,上传文件的标识串</param>
    /// <param name="multi">是否可以上传多个</param>
    /// <param name="fileTypeExts">文件类型扩展名列表</param>
    /// <param name="htmlAttributes">附加的html属性</param>
    /// <param name="editMode">是否为编辑模式</param>
    /// <param name="onlineView">是否可以在线阅读</param>
    /// <param name="onlineEdit">是否允许在线编辑</param>
    /// <param name="isRequired">是否非空验证</param>
    /// <param name="displayName">非空时提示名称</param>
    /// <param name="callBack">上传成功的回掉函数</param>
    /// <returns></returns>
    public static MvcHtmlString FileUpload<TModel>
        (
        this HtmlHelper<TModel> helper,
        string name,
        string value,
        bool multi = true,
        string fileTypeExts = null,
        object htmlAttributes = null,
        bool editMode = true,
        bool onlineView = true,
        bool onlineEdit = false,
        bool isRequired = false,
        string displayName = "",
        string callBack = ""
        )
    {
        var id = Utils.CreateTagId("fine-uploader");
 
        return FileUpload(helper, id, name, value, multi, fileTypeExts, htmlAttributes, editMode, onlineView, onlineEdit, isRequired: isRequired, displayName: displayName, callBack: callBack);
    }
 
    /// <summary>
    /// 上传文件,指定name和value不需要绑定到字段
    /// </summary>
    /// <param name="helper">上下文</param>
    /// <param name="id">容器ID</param>
    /// <param name="name">后台接收时使用的名称</param>
    /// <param name="value">值,上传文件的标识串</param>
    /// <param name="multi">是否可以上传多个</param>
    /// <param name="fileTypeExts">文件类型扩展名列表</param>
    /// <param name="htmlAttributes">附加的html属性</param>
    /// <param name="editMode">是否为编辑模式</param>
    /// <param name="onlineView">是否可以在线阅读</param>
    /// <param name="onlineEdit">是否允许在线编辑</param>
    /// <param name="width">上传文件内容显示宽度</param>
    /// <param name="isRequired">是否非空验证</param>
    /// <param name="displayName">非空时提示名称</param>
    /// <param name="callBack">上传成功的回掉函数</param>
    /// <returns></returns>
    public static MvcHtmlString FileUpload<TModel>
        (this HtmlHelper<TModel> helper,
        string id,
        string name,
        string value,
        bool multi = true,
        string fileTypeExts = null,
        object htmlAttributes = null,
        bool editMode = true,
        bool onlineView = true,
        bool onlineEdit = false,
        int width = 722,
        bool isRequired = false,
        string displayName = "",
        string callBack = "")
    {
        //内容容器
        var div = new TagBuilder("div");
        div.MergeAttribute("id", id);
        div.MergeAttribute("data-multi", multi.ToString().ToLower());
        div.MergeAttribute("data-filetypeexts", fileTypeExts);
        div.MergeAttribute("data-editmode", editMode.ToString().ToLower());
        div.MergeAttribute("data-onlineView", onlineView.ToString().ToLower());
        div.MergeAttribute("data-onlineEdit", onlineEdit.ToString().ToLower());
        div.MergeAttribute("data-canReadExts", CanReadExts.ToLower());
        div.MergeAttribute("data-canEditExts", CanEditExts.ToLower());
 
        div.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        if (width <= 0) width = 692;
        var widthStr = "width:" + width + "px";
        div.MergeAttribute("style", widthStr);
        //值保存位置
        var input = new TagBuilder("input");
        input.MergeAttribute("type", "text");
        input.MergeAttribute("id", id + "-hidden");
        input.MergeAttribute("name", name);
        input.MergeAttribute("value", value);
        input.MergeAttribute("style", "visibility: hidden;height: 0;width: 0;position:absolute;");
        if (isRequired)
        {
            input.MergeAttribute("data-val", "true");
            input.MergeAttribute("data-val-required", displayName + "不能为空");
        }
 
        //产生上传文件的区域代码
        var uploadedFileStr = CreateUploadedTag(helper, value, editMode, onlineView, onlineEdit);
 
        //隐藏已上传文件的html内容
        var hidDiv = new TagBuilder("div");
        hidDiv.AddCssClass("fileUploaderedHidDiv");
        hidDiv.MergeAttribute("style", "display:none");
        hidDiv.InnerHtml = uploadedFileStr;
 
        div.InnerHtml += hidDiv.ToString();
 
        //初始化脚本
        var script = new TagBuilder("script");
        script.InnerHtml += "jQuery(function(){createUploader('" + id + "'," + editMode.ToString().ToLower() + ",'" +
                            uploadedFileStr + "'," + multi.ToString().ToLower() + ",'" + fileTypeExts + "','" + callBack + "');});";
 
 
 
        return MvcHtmlString.Create(div + input.ToString() + script);
    }
}

 

  

 

编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示