Como detectar se as propriedades de controle do ASP.NET conter expressões DataBinding?
-
06-07-2019 - |
Pergunta
Eu tenho um controle personalizado que herda de System.Web.UI.Control
e algumas de suas propriedades podem ser declarativamente definir o uso de expressões de ligação de dados. por exemplo.
<foo:Foo runat="server" MyFoo="<%# this.GetFoo() %>" />
Agora, quando eu fizer isso eu preciso chamar .DataBind()
no controle (ou um de seus pais) para avaliar essas expressões.
O que eu gostaria de ser capaz de fazer é detectar se nenhum propriedades foram definidas desta forma e só tem automaticamente o this.DataBind()
chamada controle personalizado após OnPreRender
ou há cerca de.
Portanto, a questão : como faço para detectar se expressões de ligação de dados estão à espera de ser executado
Estou convencido de que em algum ControlBuilder
ou DataBindContext
classe vive a informação necessária para determinar isso. Eu tenho caçado em torno com refletor e não consigo encontrá-lo.
Devo acrescentar, que eu não quero pagar a sobrecarga de execução DataBind()
se há propriedades diretos foram atribuídos desta forma. É por isso que eu gostaria de detectar antes da mão. Esta classe é extremamente leve, mas eu gostaria a capacidade de propriedades declarativamente estabelecidos sem necessidade de qualquer atrás de código.
Solução
Fazendo algumas mais profundo olhar para ControlBuilder
, notei que a fábrica compilado para cada instância de controle irá anexar um manipulador de eventos DataBinding
quando há associação de dados expressões presentes. Descobri que a verificação para este parece ser um método muito confiável para determinar se os dados necessidades vinculativo para ocorrer. Aqui é a base da minha solução para o problema:
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();
}
}
}
A própria solução desactiva se nenhum processador de eventos DataBinding
está ligado ou se o controlo é manualmente dados ligado (directamente ou através de um dos pais).
Note-se que a maior parte deste código é apenas saltar através de aros para ser capaz de teste para a existência do evento. A única reflexão necessário é uma pesquisa de uma só vez para obter o object
usado como chave para EventDataBinding
.
Outras dicas
Há uma internal ArrayList
chamado SubBuilders
na classe ControlBuilder
. Para cada expressão de ligação de dados enocunters TemplateParser
, ProcessCodeBlock()
adiciona um objeto CodeBlockBuilder
com um BlockType
propriedade CodeBlockType.DataBinding
para SubBuilders
.
Então, se você pode obter um identificador para o ControlBuilder
você quiser, você deve ser capaz de reflexivamente iterar SubBuilders
e olhar para objetos do tipo CodeBlockBuilder
onde BlockType == CodeBlockType.DataBinding
.
Nota é claro que isso é todos os tipos de desagradável e estou muito desconfiado esta é a melhor maneira de resolver o seu problema central. Se você dar dois passos para trás e olhar para o problema original, talvez postar que no Stackoverflow vez -. Há muitas pessoas de super-inteligente, que pode ajudar a chegar a uma boa solução