Come rilevare se le proprietà del controllo ASP.NET contengono espressioni DataBinding?
-
06-07-2019 - |
Domanda
Ho un controllo personalizzato che eredita da System.Web.UI.Control
e alcune delle sue proprietà possono essere impostate in modo dichiarativo usando espressioni di database. per es.
<foo:Foo runat="server" MyFoo="<%# this.GetFoo() %>" />
Ora, quando lo faccio, devo chiamare .DataBind ()
sul controllo (o uno dei suoi genitori) per valutare queste espressioni.
Quello che vorrei poter fare è rilevare se le proprietà sono state impostate in questo modo e avere automaticamente la chiamata di controllo personalizzata this.DataBind ()
dopo < codice> OnPreRender o lì.
Quindi la domanda : come posso rilevare se le espressioni di database sono in attesa di essere eseguite?
Sono convinto che in alcune classi ControlBuilder
o DataBindContext
esistano le informazioni necessarie per determinarlo. Ho cercato con Reflector e non riesco a trovarlo.
Dovrei aggiungere che non voglio pagare l'overhead dell'esecuzione di DataBind ()
se non sono state assegnate proprietà dirette in questo modo. Questo è il motivo per cui vorrei rilevare prima mano. Questa classe è estremamente leggera, ma mi piacerebbe la possibilità di impostare in modo dichiarativo le proprietà senza bisogno di alcun codice.
Soluzione
Esaminando più in dettaglio ControlBuilder
, ho notato che la factory compilata per ciascuna istanza di controllo allega un gestore di eventi DataBinding
quando sono presenti espressioni di associazione dei dati. Ho scoperto che il controllo di questo sembra essere un metodo molto affidabile per determinare se è necessario eseguire l'associazione dei dati. Ecco la base della mia soluzione al 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();
}
}
}
Questa soluzione si disattiva se non è associato alcun gestore eventi DataBinding
o se il controllo è associato manualmente ai dati (direttamente o tramite un genitore).
Nota che la maggior parte di questo codice sta saltando attraverso i cerchi per poter verificare l'esistenza dell'evento. L'unica riflessione necessaria è una ricerca una tantum per ottenere oggetto
usato come chiave per EventDataBinding
.
Altri suggerimenti
Esiste un ArrayList interno
chiamato SubBuilders
nella classe ControlBuilder
. Per ogni espressione di associazione dati TemplateParser
, ProcessCodeBlock ()
aggiunge un oggetto CodeBlockBuilder
con un oggetto BlockType
CodeBlockType .DataBinding
in SubBuilders
.
Quindi, se riesci a ottenere un handle per ControlBuilder
che desideri, dovresti essere in grado di scorrere ripetutamente su SubBuilders
e cercare oggetti di tipo CodeBlockBuilder
dove BlockType == CodeBlockType.DataBinding
.
Nota che questo è di tutti i tipi di cattivo e sono davvero sospetto che questo sia il modo migliore per risolvere il tuo problema principale. Se fai due passi indietro e guardi al problema originale, magari pubblicalo su Stackoverflow - ci sono molte persone super intelligenti che possono aiutarti a trovare una buona soluzione.