• 利用Attribute实现的 MVC动态表单


    一、何谓动态表单

    最近再做一个项目,运营只是初步确定了功能,再加上项目比较复杂,所以我不好确定数据库结构

    我随时有可能在某个表中加一个属性…

    这时候,如果我有2个页面,分别是 Create 和 Edit,那我就需要对这两个页面进行修改~

    如果是更多的页面怎么办?

    那为何不根据Model,自动生成表单呢?

    网上查到一篇文章,是利用外部XML文件,好吧,我承认在一定程度上能方便一点,但写XML和写Html有什么本质区别吗?

    二、大家想要怎么样的动态表单?

    最懒的方法,只要我数据库和Model有变动,别的地方我不用动一行代码,页面就会自动生成最新的表单!

    好理想的状态~ 其实我就是为了这个目标而做的。

    虽然上面的方法最方便,但其实并不是如此,因为大部分情况下,表单中不会包含Model所有的属性(比如ID,不可能有吧?~)

    另外,Create和Edit的时候,表单也是不同的。

    所以,个人感觉,一个比较周全的方法,就是在Model的属性上添加Attribute,告诉程序,哪些属性要生成,哪些不要,它们分别在什么时候生成

    上图中,我利用了 MetadataType(为了配合Entity Framework和MVC数据验证,详细请看我另一篇文章:传送门),

    然后在MusicMetaData的属性上,加上了Attribute

    这个Attribute代表,我在Create的时候,需要输入这个属性;在Edit的时候就不需要;Order很好理解了,就是顺序

    然后怎么在页面中使用呢?

    就是这么简单,"Create"代表我现在是在Create

    后面是一个lambda表达式,传入的是 这个Model属性的名称,和类别(Textbox or TextArea?)

    最后,就可以自动生成了动态表单了

    三、上码

    复制代码
    DynamicForm
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Text;
    using System.Web.Mvc;


    namespace DS.Web.MVC
    {
    [AttributeUsage(AttributeTargets.Field
    |AttributeTargets.Property,AllowMultiple=false)]
    publicclass DynamicFormAttribute : Attribute
    {
    privateint order =0;
    publicint Order
    {
    get { return order; }
    set { order = value; }
    }
    privateint type =0;
    publicint Type
    {
    get { return type; }
    set { type = value; }
    }

    private Dictionary<string, bool> state =new Dictionary<string, bool>();
    publicboolthis[string key]
    {
    get
    {
    if (state.ContainsKey(key))
    {
    return state[key];
    }
    else
    {
    returnfalse;
    }
    }
    }

    ///<summary>
    /// 用法示例:DynamicFormAttribute("Create",true,"Edit",false)
    /// 上述用法:在创建的时候显示,在修改的时候不显示
    ///</summary>
    public DynamicFormAttribute(paramsobject[] states)
    {
    for (int k =0; k < states.Length; k +=2)
    {
    state.Add(states[k].ToString(), (
    bool)states[k +1]);
    }
    }
    }

    publicstaticclass HtmlExtensions
    {
    ///<summary>
    /// 动态生成表单
    ///</summary>
    ///<typeparam name="TModel"></typeparam>
    ///<param name="htmlHelper"></param>
    ///<param name="state">状态</param>
    ///<param name="ItemTemplate">模板</param>
    ///<returns></returns>
    publicstatic MvcHtmlString DynamicForm<TModel>(this HtmlHelper<TModel> htmlHelper, string state, Func<string, int, string> ItemTemplate)
    {
    return DynamicForm(htmlHelper, state, ItemTemplate, null, null);
    }

    ///<summary>
    /// 动态生成表单
    ///</summary>
    ///<typeparam name="TModel"></typeparam>
    ///<param name="htmlHelper"></param>
    ///<param name="state">状态</param>
    ///<param name="ItemTemplate">模板</param>
    ///<param name="AlternatingItemTemplate">隔行模板</param>
    ///<returns></returns>
    publicstatic MvcHtmlString DynamicForm<TModel>(this HtmlHelper<TModel> htmlHelper, string state, Func<string, int, string> ItemTemplate, Func<string, int, string> AlternatingItemTemplate)
    {
    return DynamicForm(htmlHelper, state, ItemTemplate, AlternatingItemTemplate, null);
    }

    ///<summary>
    /// 动态生成表单
    ///</summary>
    ///<typeparam name="TModel"></typeparam>
    ///<param name="htmlHelper"></param>
    ///<param name="state">状态</param>
    ///<param name="ItemTemplate">模板</param>
    ///<param name="SeparatorTemplate">分隔模板</param>
    ///<returns></returns>
    publicstatic MvcHtmlString DynamicForm<TModel>(this HtmlHelper<TModel> htmlHelper, string state, Func<string, int, string> ItemTemplate, Func<string> SeparatorTemplate)
    {
    return DynamicForm(htmlHelper, state, ItemTemplate, null, SeparatorTemplate);
    }


    ///<summary>
    /// 动态生成表单
    ///</summary>
    ///<typeparam name="TModel"></typeparam>
    ///<param name="htmlHelper"></param>
    ///<param name="state">状态</param>
    ///<param name="ItemTemplate">模板</param>
    ///<param name="AlternatingItemTemplate">隔行模板</param>
    ///<param name="SeparatorTemplate">分隔模板</param>
    ///<returns></returns>
    publicstatic MvcHtmlString DynamicForm<TModel>(this HtmlHelper<TModel> htmlHelper, string state, Func<string, int, string> ItemTemplate, Func<string, int, string> AlternatingItemTemplate, Func<string> SeparatorTemplate)
    {
    var sb
    =new StringBuilder();

    //分析出拥有DynamicFormAttribute的属性,并排序
    var props =new List<object[]>();
    var meta
    =typeof(TModel).GetCustomAttributes(typeof(MetadataTypeAttribute), false);
    if (meta.Length !=0)
    {
    foreach (var p in ((MetadataTypeAttribute)(meta[0])).MetadataClassType.GetProperties())
    {
    var attrs
    = p.GetCustomAttributes(typeof(DynamicFormAttribute), false);
    if (attrs.Length !=0)
    {
    var attr
    = attrs.FirstOrDefault(a => ((DynamicFormAttribute)a)[state]);
    if (attr !=null)
    {
    int index;
    for (index =0; index < props.Count; index++)
    {
    if ((int)props[index][2] > ((DynamicFormAttribute)attr).Order)
    {
    break;
    }
    }
    props.Insert(index,
    newobject[] { p.Name, ((DynamicFormAttribute)attr).Type,((DynamicFormAttribute)attr).Order }) ;
    }
    }
    }
    }


    //输出Html
    for (int k =0; k < props.Count; k += AlternatingItemTemplate ==null?1 : 2)
    {
    sb.Append(ItemTemplate(props[k][
    0].ToString(), (int)props[k][1]));
    if (k +1!= props.Count)
    {
    if (SeparatorTemplate !=null)
    {
    sb.Append(SeparatorTemplate());
    }
    if (AlternatingItemTemplate !=null)
    {
    sb.Append(AlternatingItemTemplate(props[k
    +1][0].ToString(), (int)props[k +1][1]));
    if (k +2!= props.Count && SeparatorTemplate !=null)
    {
    sb.Append(SeparatorTemplate());
    }
    }
    }
    }

    //输出
    return MvcHtmlString.Create(sb.ToString());
    }
    }
    }
    复制代码

    解释说明:

    1、上面一部分是给Model加的Attribute

    2、第二部分是HtmlHelper的扩展,用于生成Html代码

    四、用法示例

    1)生成表单,然后需要隔行更换样式,单行加上class="1",双行加上class="2",并且2行之间有特殊代码"<br/>"

    代码
    <%=Html.DynamicForm("Create", (name, type) =>"<div class=\"1\">"+ Html.TextBox(name).ToString() +"<div/>", (name, type) =>"<div class=\"2\">"+ Html.TextBox(name).ToString() +"<div/>", () =>"<br/>")%>

    2)表单中有一个属性Content,需要用 TextArea

    代码
    复制代码
    namespace EF
    {
    [MetadataType(
    typeof(MusicMetaData))]
    publicpartialclass Music
    { }

    publicclass MusicMetaData
    {
    [DynamicForm(
    "Create", true, "Edit", false, Order =3)]
    publicbool IsDeleted { get; set; }

    [DynamicForm(
    "Create", true, "Edit", false, Order =1)]
    publicbool IsExist { get; set; }

    [DynamicForm(
    "Create", true, "Edit", false, Order =2, Type =2)]
    publicstring Content { get; set; }
    }
    }
    复制代码

    注意上面,我把Content属性的Type改成了2

    <%=Html.DynamicForm("Create", (name, type) => type ==2 ? Html.TextArea(name).ToString() : Html.TextBox(name).ToString()) %>

    五、

    这个想法应该还有很多不完善的地方,所以就先不上示例程序了

    如果有什么问题,欢迎大家指出,也可以留言询问各种用法~

    所有代码均在上面那块代码段中,可以直接使用~

    别忘记添加一些引用~

  • 相关阅读:
    集训第五周动态规划 G题 回文串
    集训第五周动态规划 F题 最大子矩阵和
    集训第五周动态规划 E题 LIS
    集训第五周动态规划 D题 LCS
    集训第五周动态规划 C题 编辑距离
    集训第五周 动态规划 B题LIS
    集训第五周 动态规划 最大子段和
    防线问题
    P2486 [SDOI2011]染色
    P2146 [NOI2015]软件包管理器
  • 原文地址:https://www.cnblogs.com/chenzhonghua021/p/3001691.html
Copyright © 2020-2023  润新知