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.

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top