CSS 控件适配器工具包对事件处理的 Bug 以及修正办法
今天做一个东西,用了最近刚出来的 CSS 控件适配器工具包,对我的 TreeView 进行定制,结果发现 OnSelectedNodeChanged 事件不工作。
下面是该 TreeView 的简单的 Markup:
这个例子我是根据 CSS 控件工具包发布的程序例子模仿来写的。我们注意到,在 TreeView 的属性中,多了几个属性。
这里跟事件相关的是 OnAdaptedSelectedNodeChanged 属性。
追踪代码,发现 CSS 适配器工具包中的类,对被适配的控件的每一个事件,都添加了一个 "OnAdapted" 字样的前缀,然后通过反射找到并调用当前的页面类型中对应的处理方法。其代码如下:
(WebControlAdapterExtender.cs 中)
OK, 看到这里问题明朗了。我们通常在页面中定义的事件处理函数会是 protected 的。比如:
很明显 CSS 控件工具包的这个源码对这个反射调用的写法疏忽了。解决的办法也很简单,将上述代码改成:
如果你也发现使用了 CSS 控件工具包后,有其他控件的事件不触发的情况,可以这样来解决。
下面是该 TreeView 的简单的 Markup:
<asp:TreeView ID="tvCategories" runat="server"
CssSelectorClass="SimpleEntertainmentTreeView"
ExpandDepth="FullyExpand"
OnSelectedNodeChanged="tvCategories_SelectedNodeChanged"
OnAdaptedSelectedNodeChanged="tvCategories_SelectedNodeChanged"
/>
CssSelectorClass="SimpleEntertainmentTreeView"
ExpandDepth="FullyExpand"
OnSelectedNodeChanged="tvCategories_SelectedNodeChanged"
OnAdaptedSelectedNodeChanged="tvCategories_SelectedNodeChanged"
/>
这个例子我是根据 CSS 控件工具包发布的程序例子模仿来写的。我们注意到,在 TreeView 的属性中,多了几个属性。
这里跟事件相关的是 OnAdaptedSelectedNodeChanged 属性。
追踪代码,发现 CSS 适配器工具包中的类,对被适配的控件的每一个事件,都添加了一个 "OnAdapted" 字样的前缀,然后通过反射找到并调用当前的页面类型中对应的处理方法。其代码如下:
(WebControlAdapterExtender.cs 中)
public void RaiseAdaptedEvent(string eventName, EventArgs e)
{
string attr = "OnAdapted" + eventName;
if ((AdaptedControl != null) &&
(AdaptedControl.Attributes[attr] != null) &&
(AdaptedControl.Attributes[attr].Length > 0))
{
string delegateName = AdaptedControl.Attributes[attr];
MethodInfo method = AdaptedControl.Page.GetType().GetMethod(delegateName);
if (method != null)
{
object[] args = new object[2];
args[0] = AdaptedControl;
args[1] = e;
method.Invoke(AdaptedControl.Page, args);
}
}
}
{
string attr = "OnAdapted" + eventName;
if ((AdaptedControl != null) &&
(AdaptedControl.Attributes[attr] != null) &&
(AdaptedControl.Attributes[attr].Length > 0))
{
string delegateName = AdaptedControl.Attributes[attr];
MethodInfo method = AdaptedControl.Page.GetType().GetMethod(delegateName);
if (method != null)
{
object[] args = new object[2];
args[0] = AdaptedControl;
args[1] = e;
method.Invoke(AdaptedControl.Page, args);
}
}
}
OK, 看到这里问题明朗了。我们通常在页面中定义的事件处理函数会是 protected 的。比如:
protected void tvCategories_SelectedNodeChanged(object sender, EventArgs e) {
Response.Write("selected");
if (rlistOpType.SelectedValue == "Edit") {
LoadCurrentCategoryData();
}
}
Response.Write("selected");
if (rlistOpType.SelectedValue == "Edit") {
LoadCurrentCategoryData();
}
}
很明显 CSS 控件工具包的这个源码对这个反射调用的写法疏忽了。解决的办法也很简单,将上述代码改成:
public void RaiseAdaptedEvent(string eventName, EventArgs e)
{
string attr = "OnAdapted" + eventName;
if ((AdaptedControl != null) &&
(AdaptedControl.Attributes[attr] != null) &&
(AdaptedControl.Attributes[attr].Length > 0))
{
string delegateName = AdaptedControl.Attributes[attr];
MethodInfo method = AdaptedControl.Page.GetType().GetMethod(delegateName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (method != null)
{
object[] args = new object[2];
args[0] = AdaptedControl;
args[1] = e;
method.Invoke(AdaptedControl.Page, args);
}
}
}
{
string attr = "OnAdapted" + eventName;
if ((AdaptedControl != null) &&
(AdaptedControl.Attributes[attr] != null) &&
(AdaptedControl.Attributes[attr].Length > 0))
{
string delegateName = AdaptedControl.Attributes[attr];
MethodInfo method = AdaptedControl.Page.GetType().GetMethod(delegateName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (method != null)
{
object[] args = new object[2];
args[0] = AdaptedControl;
args[1] = e;
method.Invoke(AdaptedControl.Page, args);
}
}
}
如果你也发现使用了 CSS 控件工具包后,有其他控件的事件不触发的情况,可以这样来解决。