[英]How to detect if ASP.NET control properties contain DataBinding expressions?
I have a custom control which inherits from System.Web.UI.Control
and some of its properties can be declaratively set using databinding expressions. 我有一个自定义控件,该控件继承自
System.Web.UI.Control
,可以使用数据绑定表达式声明性地设置其某些属性。 eg 例如
<foo:Foo runat="server" MyFoo="<%# this.GetFoo() %>" />
Now, when I do that I need to call .DataBind()
on the control (or one of its parents) to evaluate these expressions. 现在,当我这样做时,我需要在控件(或
.DataBind()
控件之一.DataBind()
上调用.DataBind()
)来评估这些表达式。
What I would like to be able to do is detect if any properties were set this way and just automatically have the custom control call this.DataBind()
after OnPreRender
or there about. 我想做的是检测是否以这种方式设置了任何属性,并且只是在
OnPreRender
之后或之后自动使自定义控件调用this.DataBind()
。
So the question : how do I detect if databinding expressions are waiting to be executed? 所以问题来了 :如何检测数据绑定表达式是否正在等待执行?
I'm convinced that in some ControlBuilder
or DataBindContext
class lives the information needed to determine this. 我坚信在某些
ControlBuilder
或DataBindContext
类中可以包含确定此信息所需的信息。 I've hunted around with Reflector and cannot seem to find it. 我已经在Reflector周围搜寻,似乎找不到它。
I should add, that I don't want to pay the overhead of executing DataBind()
if no direct properties have been assigned this way. 我应该补充一点,如果没有以这种方式分配直接属性,我不想支付执行
DataBind()
的开销。 This is why I'd like to detect before hand. 这就是为什么我想先发现。 This class is extremely light but I'd like the ability to declaratively set properties without needing any code behind.
该类非常轻巧,但是我希望能够以声明方式设置属性,而无需任何代码。
Doing some deeper looking into ControlBuilder
, I noticed that the compiled factory for each control instance will attach a DataBinding
event handler when there are data binding expressions present. 在深入研究
ControlBuilder
,我注意到当存在数据绑定表达式时,每个控件实例的编译工厂将附加一个DataBinding
事件处理程序。 I've found that checking for this seems to be a very reliable method for determining if data binding needs to occur. 我发现检查这一点似乎是确定是否需要进行数据绑定的一种非常可靠的方法。 Here is the basis of my solution to the problem:
这是我解决问题的基础:
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();
}
}
}
This solution disables itself if no DataBinding
event handler is attached or if the control is manually data bound (directly or via a parent). 如果未附加
DataBinding
事件处理程序,或者如果控件是手动绑定数据(直接或通过父级)的,则此解决方案将禁用自身。
Note that most of this code is just jumping through hoops to be able to test for the existence of the event. 请注意,此代码中的大多数仅是通过跳转来测试事件是否存在。 The only reflection needed is a one-time lookup to get the
object
used as the key for EventDataBinding
. 唯一需要的反思是一次性查找以获取用作
EventDataBinding
的键的object
。
There is an internal ArrayList
called SubBuilders
on the ControlBuilder
class. 在
ControlBuilder
类上有一个internal ArrayList
称为SubBuilders
。 For each databinding expression TemplateParser
enocunters, ProcessCodeBlock()
adds a CodeBlockBuilder
object with a BlockType
property CodeBlockType.DataBinding
to SubBuilders
. 对于每个数据绑定表达式
TemplateParser
参与者, ProcessCodeBlock()
将具有BlockType
属性CodeBlockType.DataBinding
的CodeBlockBuilder
对象添加到SubBuilders
。
So if you can get a handle to the ControlBuilder
you want, you should be able to reflectively iterate over SubBuilders
and look for objects of type CodeBlockBuilder
where BlockType == CodeBlockType.DataBinding
. 因此,如果可以获取所需的
ControlBuilder
的句柄,则应该能够反射性地遍历SubBuilders
并查找CodeBlockBuilder
类型的对象,其中BlockType == CodeBlockType.DataBinding
。
Note of course this is all kinds of nasty and I'm really suspicious this is the best way to solve your core problem. 请注意,这当然令人讨厌,我真的很怀疑这是解决您的核心问题的最佳方法。 If you take two steps back and look at the original problem, maybe post that on Stackoverflow instead - there's plenty of super-smart people who can help come up with a good solution.
如果您退后两步并查看原始问题,则可以将其张贴在Stackoverflow上-有很多超级聪明的人可以帮助您找到一个好的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.