Comment détecter si les propriétés du contrôle ASP.NET contiennent des expressions DataBinding?

StackOverflow https://stackoverflow.com/questions/1417028

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.

Était-ce utile?

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 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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top