简体   繁体   English

如何检测ASP.NET控件属性是否包含DataBinding表达式?

[英]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. 我坚信在某些ControlBuilderDataBindContext类中可以包含确定此信息所需的信息。 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.DataBindingCodeBlockBuilder对象添加到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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM