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.

Foi útil?

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top