Comment détecter si les propriétés du contrôle ASP.NET contiennent des expressions DataBinding?
-
06-07-2019 - |
Question
J'ai un contrôle personnalisé qui hérite de System.Web.UI.Control
et certaines de ses propriétés peuvent être définies de manière déclarative à l'aide d'expressions de liaison de données. par exemple
<foo:Foo runat="server" MyFoo="<%# this.GetFoo() %>" />
Maintenant, je dois appeler .DataBind ()
sur le contrôle (ou l'un de ses parents) pour évaluer ces expressions.
Ce que j'aimerais pouvoir faire est de détecter si des propriétés ont été définies de cette manière et que l'appel de contrôle personnalisé soit automatiquement this.DataBind ()
après < code> OnPreRender ou là-bas.
La question : comment détecter si des expressions de liaison de données attendent d'être exécutées?
Je suis convaincu que dans certaines classes ControlBuilder
ou DataBindContext
, les informations nécessaires pour le déterminer sont conservées. J'ai cherché avec Reflector et n'arrive pas à le trouver.
Je dois ajouter que je ne veux pas payer la surcharge d'exécution de DataBind ()
si aucune propriété directe n'a été affectée de cette manière. C'est pourquoi j'aimerais détecter avant. Cette classe est extrêmement légère, mais j'aimerais pouvoir définir des propriétés de manière déclarative sans avoir besoin de code derrière.
La solution
En approfondissant l'analyse de ControlBuilder
, j'ai remarqué que la fabrique compilée pour chaque instance de contrôle attacherait un gestionnaire d'événements DataBinding
lorsqu'il existe des expressions de liaison de données. J'ai constaté que la vérification de cela semble être une méthode très fiable pour déterminer si une liaison de données doit avoir lieu. Voici la base de ma solution au problème:
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();
}
}
}
Cette solution se désactive si aucun gestionnaire d'événements DataBinding
n'est attaché ou si le contrôle est lié manuellement aux données (directement ou via un parent).
Notez que la majeure partie de ce code saute juste à travers des obstacles pour pouvoir vérifier l’existence de l’événement. La seule réflexion nécessaire est une recherche ponctuelle pour obtenir l'objet
utilisé comme clé pour EventDataBinding
.
Autres conseils
Il existe une interne ArrayList
appelée SubBuilders
sur la classe ControlBuilder
. Pour chaque expression de liaison de données TemplateParser
, ProcessCodeBlock ()
ajoute un objet CodeBlockBuilder
avec une propriété BlockType
, CodeBlockType .DataBinding
à SubBuilders
.
Ainsi, si vous pouvez obtenir un descripteur du ControlBuilder
souhaité, vous devriez pouvoir effectuer une itération réfléchie sur SubBuilders
et rechercher des objets de type CodeBlockBuilder
où BlockType == CodeBlockType.DataBinding
.
Notez bien sûr que ce sont toutes sortes de problèmes et que je suis vraiment méfiant. C’est la meilleure façon de résoudre votre problème principal. Si vous prenez deux pas en arrière et examinez le problème initial, signalez-le peut-être sur Stackoverflow: de nombreuses personnes extrêmement intelligentes peuvent vous aider à trouver une bonne solution.