Как определить, содержат ли свойства элемента управления ASP.NET выражения DataBinding? - PullRequest
0 голосов
/ 13 сентября 2009

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

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

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

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

Итак, вопрос : как я могу определить, ожидают ли выполнения выражения привязки данных?

Я убежден, что в каком-то классе ControlBuilder или DataBindContext живет информация, необходимая для определения этого. Я охотился с Reflector и не могу его найти.

Я должен добавить, что я не хочу оплачивать накладные расходы на выполнение DataBind(), если никакие прямые свойства не были назначены таким образом. Вот почему я хотел бы обнаружить заранее. Этот класс очень легкий, но я хотел бы иметь возможность декларативно устанавливать свойства без необходимости кода.

Ответы [ 2 ]

2 голосов
/ 19 сентября 2009

Глубже изучая 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.

0 голосов
/ 13 сентября 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...