我有一个继承自 System.Web.UI.Control 的自定义控件,并且可以使用数据绑定表达式以声明方式设置它的一些属性。 e.g。

<foo:Foo runat="server" MyFoo="<%# this.GetFoo() %>" />

现在,当我这样做时,我需要在控件(或其父节点之一)上调用 .DataBind()来评估这些表达式。

我希望能够做的是检测 if 是否以这种方式设置了任何属性,只是在<<>之后自动拥有自定义控件 this.DataBind()代码> OnPreRender 或那里。

所以问题:如何检测数据绑定表达式是否等待执行?

我确信在某些 ControlBuilder DataBindContext 类中存在确定此信息所需的信息。我一直在寻找Reflector并且似乎无法找到它。

我应该补充一点,如果没有以这种方式分配直接属性,我不想支付执行 DataBind()的开销。这就是为什么我要事先发现。这个类非常轻,但我希望能够声明性地设置属性而不需要任何代码。

有帮助吗?

解决方案

深入研究 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 的键。

其他提示

ControlBuilder 类上有一个名为 SubBuilders 内部ArrayList 。对于每个数据绑定表达式 TemplateParser enocunters, ProcessCodeBlock()使用 BlockType 属性 CodeBlockType添加 CodeBlockBuilder 对象.DataBinding SubBuilders

因此,如果您可以获得所需的 ControlBuilder 句柄,您应该能够反复迭代 SubBuilders 并查找 CodeBlockBuilder <的类型的对象/ code>其中 BlockType == CodeBlockType.DataBinding

当然注意这是各种令人讨厌的,我真的很怀疑这是解决你的核心问题的最佳方法。如果你退两步并查看原始问题,也许可以在Stackoverflow上发布 - 有很多超级聪明的人可以帮助我们找到一个好的解决方案。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top