Как определить, содержат ли свойства элемента управления ASP.NET выражения DataBinding?
-
06-07-2019 - |
Вопрос
У меня есть пользовательский элемент управления, который наследуется от 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 - есть множество супер-умных людей, которые могут помочь найти хорошее решение.