1、分析
不知道大家在使用ASP.NET AJAX Control Toolkit里的各个Extender控件时,有没有接触过ResolveControlID事件?这个事件在官方也只用了很少的笔墨来描述。的确,这个事件不太常用,看看ASP.NET AJAX的演示站点,根本没有使用过ResolveControlID事件。
那么这个事件难道没有什么用吗?其实不然。这个事件原本不存在于ASP.NET AJAX中,是ASP.NET AJAX Control Toolkit为了方便Extender的开发,而是现在ExtenderControlBase类里的。ASP.NET AJAX Control Toolkit是个非常重要的东西,他提供的ExtenderControlBase类基于ASP.NET AJAX中的ExtenderBase类,提供了许多有用的扩展,大大方便了Extender的开发。ResolveControlID事件就是其中一个。它的作用是帮助Extender找到它需要的控件。
每个Extender控件都会有XXXXID属性(例如TargetControlID),它们在开发是都会使用IDReferenceAttribute进行标注,这说明这些属性的“含义”并非只是一个简单的字符串,它们的作用是表示一个控件。换句话说,就是在Extender工作时提供它所需要的各个控件。大家平时在使用Extender控件时,往往会把Extender和它需要的控件放在同一个Web User Control或者Page中,这时只要为那些ID属性指定对应的控件ID即可。但是如果Extender需要的控件和Extender本身并不在同一个Web User Contorl或Page中时,该如何告诉Extender,应该使用哪些控件呢?
这就是ResolveControlID事件的作用了。如果要说得更加“专业”一些,ResolveControlID事件的作用是帮助Extender找到不同Naming Container中的控件。Naming Container是ASP.NET页面模型的概念,它提供了一种“容器”,目的是能够封装一些控件,使不同容器间的控件不会因为某些原因而产生冲突(例如服务器端ID)。有了Naming Container,我们可以在页面上放置多个Web User Control,而每个Web User Control中很有可能会有相同服务器ID的控件,但是它们不会互相冲突。一个Naming Container就是一个实现了INamingContainer接口的控件,它没有任何方法,它的作用仅仅是为了“标记”。我们平时接触的Control类和Page类都是先了这个接口,也就是说它们都是Naming Container。
如果我们在浏览器中查看页面中HTML元素的ID,经常可以发现有“xxxx$xxxx$xxx…”这种形式的ID,这也是Naming Container的作用,它也能保证了每个HTML元素的客户端ID的唯一性。而控件的客户端ID可以通过它在服务器端的ClientID属性获得,不过这就是另外的话题了。
那么ResolveControlID事件是如何生效的呢?ResoveControlID的“事件”参数类型为ResolveControlEventArgs类型,它有一个可写的Control属性。当Extender无法在自己所在的Naming Container中找到控件时,就会触发ResolveControlID事件,然后使用“事件”参数的Control属性作为找到的控件。我们要做的就是在响应这个事件时设定ResolveControlEventArgs.Control属性,给定合适的控件。
其实ResolveControlID事件就是这么简单。
2、示例
其实听了上面的描述,相信大家已经知道如何响应ResolveControlID事件了。不过在这里,我想用一种比较统一的解决方案来实现ResolveControlID。
Naming Container其实也就是包含了其它控件,自然可以是别的Naming Container,因此会形成了“级别”。我们不如把这样的“级别”通过指定Extender的那些ID属性描述出来,然后可以顺着Naming Container的级别一直找下去。具体的做法,我们通过一个使用ModalPopupExtender的示例来看一下吧。
首先,我们要形成不同的Naming Container。那么在这里,我们把弹出的Panel、OK Button以及Cancel Button放在一个Web User Control中,如下:
<asp:Panel ID="ModalDialogPanel" runat="server" Width="300" style="padding: 10px; border:solid 1px black;">ASP.NET AJAX is a free framework for building a new...<br /><br /><asp:Button ID="OkButton" runat="server" Text="OK" /><asp:Button ID="CancelButton" runat="server" Text="Cancel" /> </asp:Panel>
然后就在Page里使用ModalPopupExtener了,请注意,我们为那些ID属性指定了使用逗号分割的字符串,这种方法就表示了Naming Container的级别。例如PopupControlID为“ModalDialog, ModalDialogPanel”,就表示了弹出的控件是ID为ModalPopupDialog的Naming Container(ModalDialog控件)里的ModalDialogPanel控件(可以在ModalDialog.ascx文件中找到)。如下:
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager><asp:LinkButton ID="LinkButton1" runat="server">Click Here to Popup a Modal Dialog </asp:LinkButton><ajaxToolkit:ModalPopupExtender ID="ModalPopupExtender" runat="server"TargetControlID="LinkButton1"PopupControlID="ModalDialog, ModalDialogPanel"OkControlID="ModalDialog, OkButton"CancelControlID="ModalDialog, CancelButton"OnResolveControlID="ModalPopupExtender_ResolveControlID" /><uc1:ModalDialog ID="ModalDialog" runat="server" />
最后就似乎要响应ResolveControlID事件了,相信大家能够很轻松的得出它的实现方式。如下:
protected void ModalPopupExtender_ResolveControlID(object sender, ResolveControlEventArgs e) {if (e.ControlID == null) return;string[] controlIds = e.ControlID.Split(',');Control result = this;foreach (string id in controlIds){result = result.FindControl(id.Trim());}e.Control = result; }
其实ResolveControlID事件的作用和实现就是这么简单。下面就是使用效果:
点击这里下载示例文件。