我有一个继承自System.Web.UI.Control
的自定义控件,可以使用数据绑定表达式以声明方式设置其某些属性。 e.g。
<foo:Foo runat="server" MyFoo="<%# this.GetFoo() %>" />
现在,当我这样做时,我需要在控件(或其父节点之一)上调用.DataBind()
来评估这些表达式。
我希望能够做的是检测,如果以这种方式设置任何属性,并在this.DataBind()
之后自动拥有自定义控件OnPreRender
所以问题:如何检测数据绑定表达式是否等待执行?
我确信在某些ControlBuilder
或DataBindContext
班级中存在确定此信息所需的信息。我一直在寻找Reflector并且似乎无法找到它。
我应该补充一点,如果没有以这种方式分配直接属性,我不想支付执行DataBind()
的开销。这就是为什么我要事先发现。这个类非常轻,但我希望能够声明性地设置属性而不需要任何代码。
答案 0 :(得分:2)
深入研究ControlBuilder
,我注意到当存在数据绑定表达式时,每个控件实例的编译工厂将附加DataBinding
事件处理程序。我发现检查这个似乎是一种非常可靠的方法,用于确定是否需要进行数据绑定。以下是我解决问题的基础:
using System;
using System.Reflection;
using System.Web.UI;
public class AutoDataBindControl : Control
{
private static readonly object EventDataBinding;
private bool needsDataBinding = false;
static AutoDataBindControl()
{
try
{
FieldInfo field = typeof(Control).GetField(
"EventDataBinding",
BindingFlags.NonPublic|BindingFlags.Static);
if (field != null)
{
AutoDataBindControl.EventDataBinding = field.GetValue(null);
}
}
catch { }
if (AutoDataBindControl.EventDataBinding == null)
{
// effectively disables the auto-binding feature
AutoDataBindControl.EventDataBinding = new object();
}
}
protected override void DataBind(bool raiseOnDataBinding)
{
base.DataBind(raiseOnDataBinding);
// flag that databinding has taken place
this.needsDataBinding = false;
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// check for the presence of DataBinding event handler
if (this.HasEvents())
{
EventHandler handler = this.Events[AutoDataBindControl.EventDataBinding] as EventHandler;
if (handler != null)
{
// flag that databinding is needed
this.needsDataBinding = true;
this.Page.PreRenderComplete += new EventHandler(this.OnPreRenderComplete);
}
}
}
void OnPreRenderComplete(object sender, EventArgs e)
{
// DataBind only if needed
if (this.needsDataBinding)
{
this.DataBind();
}
}
}
如果没有附加DataBinding
事件处理程序,或者控件是手动数据绑定(直接或通过父级),此解决方案将自行禁用。
请注意,此代码中的大多数只是跳过箍,以便能够测试事件的存在。所需的唯一反映是一次性查找,以将object
用作EventDataBinding
的关键字。
答案 1 :(得分:0)
internal ArrayList
课程中有一个名为SubBuilders
的{{1}}。对于每个数据绑定表达式ControlBuilder
enocunters,TemplateParser
会将ProcessCodeBlock()
对象与CodeBlockBuilder
属性BlockType
添加到CodeBlockType.DataBinding
。
因此,如果您可以获得所需的SubBuilders
句柄,则应该能够反复迭代ControlBuilder
并查找SubBuilders
类型的对象CodeBlockBuilder
当然注意这是各种令人讨厌的,我真的很怀疑这是解决你的核心问题的最佳方法。如果你退两步并查看原始问题,也许可以在Stackoverflow上发布 - 有很多超级聪明的人可以帮助我们找到一个好的解决方案。