利用Attribute实现的 MVC动态表单

一、何谓动态表单

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

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

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

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

 

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

 

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

 

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

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

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

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

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

 

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

2010080501480516.jpg

 

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

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

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

 

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

2010080501515070.jpg

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

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

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

 

三、上码

 

ContractedBlock.gif ExpandedBlockStart.gif 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 )]
public class DynamicFormAttribute : Attribute
{
private int order = 0 ;
public int Order
{
get { return order; }
set { order = value; }
}
private int type = 0 ;
public int Type
{
get { return type; }
set { type = value; }
}

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

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

public static class HtmlExtensions
{
/// <summary>
/// 动态生成表单
/// </summary>
/// <typeparam name="TModel"></typeparam>
/// <param name="htmlHelper"></param>
/// <param name="state"> 状态 </param>
/// <param name="ItemTemplate"> 模板 </param>
/// <returns></returns>
public static 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>
public static 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>
public static 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>
public static 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,
new object [] { 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/>"

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
<% = 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

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
namespace EF
{
[MetadataType(
typeof (MusicMetaData))]
public partial class Music
{ }

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

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

[DynamicForm(
" Create " , true , " Edit " , false , Order = 2 , Type = 2 )]
public string Content { get ; set ; }
}
}

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

 

 

 

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

 

 

 

五、

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

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

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

别忘记添加一些引用~

转载于:https://www.cnblogs.com/dozer/archive/2010/08/05/DynamicForm.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值