ASP.NETコントロールプロパティにDataBinding式が含まれているかどうかを検出する方法

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

質問

System.Web.UI.Control を継承するカスタムコントロールがあり、その一部のプロパティはデータバインディング式を使用して宣言的に設定できます。例:

<foo:Foo runat="server" MyFoo="<%# this.GetFoo() %>" />

今、その場合、コントロール(またはその親の1つ)で .DataBind()を呼び出して、これらの式を評価する必要があります。

できるようにしたいのは、この方法でプロパティが設定された場合に を検出し、< code> OnPreRender またはその付近。

それでは質問:データバインディング式の実行待ちを検出するにはどうすればよいですか

一部の ControlBuilder または DataBindContext クラスには、これを判断するために必要な情報が含まれていると確信しています。 Reflectorを探し回っていますが、見つけられないようです。

追加する必要があるのは、この方法で直接プロパティが割り当てられていない場合、 DataBind()を実行するオーバーヘッドを支払いたくないということです。これが私が事前に検出したい理由です。このクラスは非常に軽量ですが、コードビハインドを必要とせずに宣言的にプロパティを設定できる機能が欲しいです。

役に立ちましたか?

解決

ControlBuilder をさらに詳しく調べると、データバインディング式が存在する場合、各コントロールインスタンスのコンパイルされたファクトリが DataBinding イベントハンドラをアタッチすることに気付きました。これを確認することは、データバインディングを行う必要があるかどうかを判断するための非常に信頼性の高い方法であることがわかった。ここに私の問題の解決の基礎があります:

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();
        }
    }
}

このソリューションは、 DataBinding イベントハンドラーがアタッチされていない場合、またはコントロールが(直接または親を介して)手動でデータバインドされている場合、それ自体を無効にします。

このコードのほとんどは、イベントの存在をテストできるようにするためにフープをジャンプしているだけです。唯一必要なリフレクションは、 EventDataBinding のキーとして使用される object を取得するための1回限りのルックアップです。

他のヒント

ControlBuilder クラスには、 SubBuilders という internal ArrayList があります。各データバインディング式 TemplateParser enocuntersに対して、 ProcessCodeBlock() BlockType プロパティ CodeBlockTypeを持つ CodeBlockBuilder オブジェクトを追加します.DataBinding から SubBuilders へ。

したがって、必要な ControlBuilder へのハンドルを取得できる場合、 SubBuilders をリフレクションで反復処理し、 CodeBlockBuilder BlockType == CodeBlockType.DataBinding の場合。

もちろんこれはあらゆる種類の厄介なものであり、これがコアの問題を解決する最善の方法であると本当に疑っています。 2ステップ前に戻って元の問題を確認する場合は、代わりにStackoverflowに投稿することをお勧めします-優れた解決策を考え出すのに役立つ非常に賢い人がたくさんいます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top