GridView 数据绑定扩展-- 动态添加数据列,绑定方法
2011-02-14 00:16
597 查看
GridView 是ASP.NET中表格数据显示控件中的一种,可以支持数据绑定,绑定的数据源我们一般用实现IEnumerable<T>接口的对象,T可以是任何一个CLR类(当然还有一些其他的数据源格式),这些大家基本都很熟悉,但是最近碰到一个新的需求:
像有一个类似于:
public class Book
{
public int ID { get; set; }
public string Name { get; set; }
public Dictionary<string, object> ExtendProperties { get; set; }
}
其中ExtendProperties 是用来存储不同用户自定义的扩展属性的,用键值对的形式保存,Key保存扩展属性名,Value保存扩展属性值,每个用户可能的扩展属性个数和键值都不一样。
现在,如果我们需要把List<Book>绑定在GridView上面,但是希望将ExtendProperties中的扩展属性也都显示出来,而且相应的Key显示在Column的Header,而Value则显示在相应的Cell中。
起初想沿着GridView绑定一般数据的思路考虑,看是否能够通过动态属性的方式将ExtendProperties中的键值对匹配成相应的对象属性,(没有测试是否能够成功),但是又觉得数据绑定是控件的事情,这个不应该由数据本身来负责,那我们能否通过修改GridView本身的行为来达到这个目的呢?? 答案是肯定的!
我们都知道,GridView本身是有一个AutoGenerateColumns的属性,如果设置为True的话,GridView将自动添加一些列,这些列对应Book中的每一个可绑定的属性,这里是用PropertyDescriptor来实现的(好像是考虑到DesignMode,而没有用Type来做反射)。根据这个思路,我们可以先看看AutoGenerateColumns到底对GridView有哪些影响以及GridView本身是如何生成Columns的。
通过查看GridView的源码,我们可以看到几个重要的方法:
代码
public class ExtBouldField :BoundField
{
#region Ctor
public ExtBouldField()
: base()
{
UseMethodBinding = false;
}
#endregion
#region Properties
public bool UseMethodBinding
{
get;
set;
}
public string MethodName
{
get;
set;
}
public string MethodParam
{
get;
set;
}
#endregion
#region Overrided methods
protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
{
Control child = null;
Control control2 = null;
bool needBinding = (!UseMethodBinding && !String.IsNullOrEmpty(DataField))
||(UseMethodBinding && !String.IsNullOrEmpty(MethodName));
if ((((rowState & DataControlRowState.Edit) != DataControlRowState.Normal) && !this.ReadOnly) || ((rowState & DataControlRowState.Insert) != DataControlRowState.Normal))
{
TextBox box = new TextBox();
box.ToolTip = this.HeaderText;
child = box;
if ((needBinding) && ((rowState & DataControlRowState.Edit) != DataControlRowState.Normal))
{
control2 = box;
}
}
else if (needBinding)
{
control2 = cell;
}
if (child != null)
{
cell.Controls.Add(child);
}
if ((control2 != null) && base.Visible)
{
control2.DataBinding += new EventHandler(this.OnDataBindField);
}
}
protected override object GetValue(Control controlContainer)
{
if (UseMethodBinding)
{
if (String.IsNullOrEmpty(MethodName))
{
throw new HttpException("DataItem No MethodName");
}
object component = null;
if (controlContainer == null)
{
throw new HttpException("DataControlField_NoContainer");
}
component = DataBinder.GetDataItem(controlContainer);
if (component != null)
{
MethodInfo bindingMethodInfo = component.GetType().GetMethod(MethodName);
if (bindingMethodInfo == null)
{
throw new HttpException(String.Format("Not Found the Method:{0}", MethodName));
}
return bindingMethodInfo.Invoke(component, new object[] { MethodParam });
}
return component;
}
return base.GetValue(controlContainer);
}
#endregion
}
其中:
UsingMethodBinding 用来指明是用方法绑定还是原来的基于属性的绑定;
MethodName 用来指明通过绑定对象的哪个方法来获取绑定数据;
MethodParam 用来指明方法的参数(如果是代码设置该属性的话,可以让他为任何类型,但是这里只是用string,为了使ASPX页面也能直接设置该参数的值)。
到这里,原来碰到的问题都解决了:
通过继承 GridView 并且重载 CreateColumns() 添加自己想要的 Column,根据扩展属性中的键值对生成Column。
通过继承 BouldField,并且重载 InitializeDataCell() 和 GetValue() 实现自己希望的绑定方法,实现可以基于方法的数据绑定,从而可以将扩展属性中的键值绑定到对应的Cell中。
上面的例子只有考虑第一次加载的情况,如果页面有PostBack,则还需要改进一下,这个需要谢谢geass..,由于原来的目的只是做这个扩展属性的绑定是否可行性研究,所以存在一些bug。 不过在新的可下载的代码中,这个由PostBack产生的问题已经解决了,具体的可见代码。
ExtendPropertiesBindingForGridView.rar
像有一个类似于:
public class Book
{
public int ID { get; set; }
public string Name { get; set; }
public Dictionary<string, object> ExtendProperties { get; set; }
}
其中ExtendProperties 是用来存储不同用户自定义的扩展属性的,用键值对的形式保存,Key保存扩展属性名,Value保存扩展属性值,每个用户可能的扩展属性个数和键值都不一样。
现在,如果我们需要把List<Book>绑定在GridView上面,但是希望将ExtendProperties中的扩展属性也都显示出来,而且相应的Key显示在Column的Header,而Value则显示在相应的Cell中。
起初想沿着GridView绑定一般数据的思路考虑,看是否能够通过动态属性的方式将ExtendProperties中的键值对匹配成相应的对象属性,(没有测试是否能够成功),但是又觉得数据绑定是控件的事情,这个不应该由数据本身来负责,那我们能否通过修改GridView本身的行为来达到这个目的呢?? 答案是肯定的!
我们都知道,GridView本身是有一个AutoGenerateColumns的属性,如果设置为True的话,GridView将自动添加一些列,这些列对应Book中的每一个可绑定的属性,这里是用PropertyDescriptor来实现的(好像是考虑到DesignMode,而没有用Type来做反射)。根据这个思路,我们可以先看看AutoGenerateColumns到底对GridView有哪些影响以及GridView本身是如何生成Columns的。
通过查看GridView的源码,我们可以看到几个重要的方法:
代码
public class ExtBouldField :BoundField
{
#region Ctor
public ExtBouldField()
: base()
{
UseMethodBinding = false;
}
#endregion
#region Properties
public bool UseMethodBinding
{
get;
set;
}
public string MethodName
{
get;
set;
}
public string MethodParam
{
get;
set;
}
#endregion
#region Overrided methods
protected override void InitializeDataCell(DataControlFieldCell cell, DataControlRowState rowState)
{
Control child = null;
Control control2 = null;
bool needBinding = (!UseMethodBinding && !String.IsNullOrEmpty(DataField))
||(UseMethodBinding && !String.IsNullOrEmpty(MethodName));
if ((((rowState & DataControlRowState.Edit) != DataControlRowState.Normal) && !this.ReadOnly) || ((rowState & DataControlRowState.Insert) != DataControlRowState.Normal))
{
TextBox box = new TextBox();
box.ToolTip = this.HeaderText;
child = box;
if ((needBinding) && ((rowState & DataControlRowState.Edit) != DataControlRowState.Normal))
{
control2 = box;
}
}
else if (needBinding)
{
control2 = cell;
}
if (child != null)
{
cell.Controls.Add(child);
}
if ((control2 != null) && base.Visible)
{
control2.DataBinding += new EventHandler(this.OnDataBindField);
}
}
protected override object GetValue(Control controlContainer)
{
if (UseMethodBinding)
{
if (String.IsNullOrEmpty(MethodName))
{
throw new HttpException("DataItem No MethodName");
}
object component = null;
if (controlContainer == null)
{
throw new HttpException("DataControlField_NoContainer");
}
component = DataBinder.GetDataItem(controlContainer);
if (component != null)
{
MethodInfo bindingMethodInfo = component.GetType().GetMethod(MethodName);
if (bindingMethodInfo == null)
{
throw new HttpException(String.Format("Not Found the Method:{0}", MethodName));
}
return bindingMethodInfo.Invoke(component, new object[] { MethodParam });
}
return component;
}
return base.GetValue(controlContainer);
}
#endregion
}
其中:
UsingMethodBinding 用来指明是用方法绑定还是原来的基于属性的绑定;
MethodName 用来指明通过绑定对象的哪个方法来获取绑定数据;
MethodParam 用来指明方法的参数(如果是代码设置该属性的话,可以让他为任何类型,但是这里只是用string,为了使ASPX页面也能直接设置该参数的值)。
到这里,原来碰到的问题都解决了:
通过继承 GridView 并且重载 CreateColumns() 添加自己想要的 Column,根据扩展属性中的键值对生成Column。
通过继承 BouldField,并且重载 InitializeDataCell() 和 GetValue() 实现自己希望的绑定方法,实现可以基于方法的数据绑定,从而可以将扩展属性中的键值绑定到对应的Cell中。
上面的例子只有考虑第一次加载的情况,如果页面有PostBack,则还需要改进一下,这个需要谢谢geass..,由于原来的目的只是做这个扩展属性的绑定是否可行性研究,所以存在一些bug。 不过在新的可下载的代码中,这个由PostBack产生的问题已经解决了,具体的可见代码。
ExtendPropertiesBindingForGridView.rar
相关文章推荐
- GridView 动态添加模板列并绑定数据 实现从外部直接传入控件 和 绑定字段参数
- ASP.NET2.0中给GridView动态添加模板列并自动绑定数据
- 动态添加gridView 并绑定数据
- 后台给GridView绑定数据时给每一行添加一个JS方法
- GridView动态添加列并判断绑定数据DataTable的列类型控制展示内容
- ASP.NET2.0中给GridView动态添加模板列并自动绑定数据
- 动态添加GRIDVIEW内容 和数据绑定
- GridView动态添加模板列(数据绑定)
- GridView动态添加模板列(并为其添加事件和自动绑定数据)
- ASP.NET2.0中给GridView动态添加模板列并自动绑定数据
- GridView动态添加模板列并自动绑定数据
- Repeater控件使用方法(绑定数据、添加序号列)
- GridView中给DropDownList动态绑定数据,及选择列表值后自动更新数据库
- ComboBox 经验总结[动态绑定数据之后,静态添加一条数据]
- C#中GridView动态添加列的实现方法
- 自定义DataList,GridView通过DataBinder.Eval方法绑定的数据
- ComboBox 经验总结[动态绑定数据之后,静态添加一条数据]
- bootstrap-treeview 扩展addNode deleteNode方法 动态添加删除子节点的方法
- GridView动态添加模板列,并解决数据列PostBack后数据丢失问题!
- GridView 动态添加一个view(加号图标),数据等于9的时候,加号图标隐藏