构思的起因
曾经在浏览MSDN时,看到这样一个接口:IExtenderProvider 接口 。它的描述是:定义将属性扩展到容器中的其他组件的接口。当时因为有些不理解,出于好奇,于是继续看下去,发现了与它相关的一个例子:ToolTip 控件即是一个扩展程序提供程序。当向某个 Form 添加 ToolTip 控件时,将向该窗体上的所有其他控件的属性列表中添加 ToolTip 属性。我当时就被这个例子吸引住了,因为我当时正好在看有关控件的数据绑定方面的文档,灵感让我联想到,如果可以用一个组件来把多个控件的属性的数据绑定管理起来的话,其功能是多么强大啊!以我以往的项目开发经验,我知道其页面的输入控件与业务逻辑类的数据相互赋值是让人十分烦闷的,而且有时这样的代码又特别的多,于是我就开始认真地构思一个这样的组件。
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
初步构思
我初步的设想是:设计一个组件ControlManager,实现IextenderProvider接口,用它来给页面上的其它输入控件添加相应的数据绑定属性,然后通过这样的属性,在设计时,使页面上的每一个输入控件与后台业务相关的Model对象的一个属性相对应进行绑定。这样,我们只要对这个ControlManager组件进行简单的代码操作,便可以使对象中的属性显示在相应的输入控件上。相应的,如果输入控件上的值有变化,可以自动地改变Model对象中相应属性的值。
于是我开始仔细在MSDN中查找相关的文档,在“实现扩展程序提供程序”部分,只发现window程序的例子,asp.net程序只有这样一句描述:注意 Windows 窗体控件的扩展程序提供程序的实现与 ASP.NET 服务器控件的扩展程序提供程序的实现不同。 但具体有什么不同,怎样实现却没有说。
我想,只能自己实验下了。
开始试验
首先,我写了一个继承了System.ComponentModel.Component类的ControlManager类,用它实现了IextenderProvider接口,一个DataSource属性,写了一个BindData()方法,主要代码如下:
[ProvideProperty("DataSource", typeof(System.Web.UI.WebControls.WebControl))]
[ProvideProperty("PropertyName", typeof(System.Web.UI.WebControls.WebControl))]
public class ControlManager : System.ComponentModel.Component , IextenderProvider
{
#region IExtenderProvider
public bool CanExtend(object extendee)
{
if (extendee is System.Web.UI.WebControls.WebControl && !(extendee is ControlManager) && !(extendee is System.Web.UI.Page) )
{
return true;
}
return false;
}
//此属性设想用于设置要绑定的后台对象的类型
private Hashtable m_DataSource = new Hashtable();
[Category("ControlManager")]
[Description("需要绑定到数据源的标识")]
[DefaultValue(null)]
public string GetDataSource( System.Web.UI.WebControls.WebControl c )
{
return (string) m_DataSource[c];
}
public void SetDataSource(System.Web.UI.WebControls.WebControl c, string value )
{
if( value == null || value.Length == 0 )
{
m_DataSource.Remove(c);
}
else
{
m_DataSource[c] = value;
}
}
//此属性设想用于设置要绑定的后台对象的属性
private Hashtable m_PropertyName = new Hashtable();
[Category("ControlManager")]
[Description("需要绑定到数据源的属性")]
[DefaultValue(null)]
public string GetPropertyName(System.Web.UI.WebControls.WebControl c )
{
return (string) m_PropertyName[c];
}
public void SetPropertyName(System.Web.UI.WebControls.WebControl c, string value )
{
if( value == null || value.Length == 0 )
{
m_PropertyName.Remove(c);
}
else
{
m_PropertyName[c] = value;
}
}
//此方法用于把后台对象与控件进行数据绑定
//source为对象,用name来找到需绑定的控件
public void BindData( object source, string name )
{
foreach(System.Web.UI.WebControls.WebControl c in m_DataSource.Keys )
{
try
{
if( ((string)m_DataSource[c]) == name ) //找到需要绑定数据的控件
{
//进行数据绑定或赋值。此处没想好,可能需要反射。
//实验阶段如果代码能够执行到这就可以了。可是在调试中发现 m_DataSource.count=0 ! 即,在控件上设置的值没有保存在组件中。
}
}
catch( Exception e )
{
throw e;
}
}
}
#endregion
}
在把类编译通过后,把其添加到工具栏中,然后建立测试项目与测试页。在测试页中放置了几个文本框,然后把ControlManager组件从工具栏中拖到页面上。查看其它的文本框,发现每个文本框上都多出了两个属性“controlManager1上的DataSource”和“controlManager1 上的PropertyName”。
说明接口IextenderProvider实现成功。
于是接下来我为每个文本框中的扩展属性进行设置,设置如下:
TextBox1 :
DataSource : TestModel
PropertyName : Name
TextBox2 :
DataSource : TestModel
PorpertyName : Age
于是页中放置一个button控件,在其click事件中做如下调用:
TestModel tm = new TestModel();
Tm.Name = “123”;
Tm.Age = “23”;
ControlManager1.DataBind(tm,“TestModel”);
然后我调试,程序在执行到DataBind方法内后,其foreach循环一次也没有执行,立即窗口中发现m_DataSource.count=0。
由此我设想可能是因为页面刷新之后,其数据没有保存的原因,于是我试着把ControlManager类继承System.Web.UI.WebControls.WebControl类,做为一个不可见控件,然后用ViewState来保持其设置的值。