Как определить, содержат ли свойства элемента управления ASP.NET выражения DataBinding?

StackOverflow https://stackoverflow.com/questions/1417028

Вопрос

У меня есть пользовательский элемент управления, который наследуется от System.Web.UI.Control , и некоторые его свойства могут быть декларативно установлены с помощью выражений привязки данных. например.

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

Теперь, когда я это делаю, мне нужно вызвать .DataBind () для элемента управления (или одного из его родителей), чтобы оценить эти выражения.

Я хотел бы иметь возможность обнаруживать в if какие-либо свойства, установленные таким образом, и просто автоматически вызывать вызов настраиваемого элемента управления this.DataBind () после < code> 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 или если элемент управления связан с данными вручную (напрямую или через родительский элемент).

Обратите внимание, что большая часть этого кода просто перепрыгивает через обручи, чтобы иметь возможность проверить наличие события. Единственное необходимое отражение - это однократный поиск, чтобы получить объект , используемый в качестве ключа для EventDataBinding .

Другие советы

В классе ControlBuilder есть внутренний ArrayList с именем SubBuilders . Для каждого enocunters выражения TemplateParser ProcessCodeBlock () добавляет объект CodeBlockBuilder со свойством BlockType CodeBlockType .DataBinding с SubBuilders .

Таким образом, если вы можете получить дескриптор ControlBuilder , который вы хотите, вы сможете рефлексивно перебирать SubBuilders и искать объекты типа CodeBlockBuilder где BlockType == CodeBlockType.DataBinding .

Заметьте, конечно, что это все виды мерзости, и я действительно подозреваю, что это лучший способ решить вашу основную проблему. Если вы сделаете два шага назад и посмотрите на исходную проблему, возможно, вместо этого опубликуйте ее в Stackoverflow - есть множество супер-умных людей, которые могут помочь найти хорошее решение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top