2011-08-05 17 views
3

ページのライフサイクル中に特定のイベント中にのみメソッドにアクセスできるようにする方法がありますか?たとえば、System.Web.UI.Pageという拡張子を持ち、PrependTitleメソッドを追加しています。イベント中に強制的に実行するメソッド

私はまた別のマスターページを埋め込むマスターページを持っています。最初のマスターページはベースタイトル(Google)を設定し、次のマスターページはタイトル(カレンダー)を前に付け、ページもタイトルを前に付けます(2011年5月21日)。

結果は次のようになります。

21 May 2011 :: Calendar :: Google

そして、これはPrependTitlePage_Initイベント中に実行された場合です。だから、

Google

、質問に私をもたらします:方法が唯一の指定されたライフサイクルイベント中にアクセスすることを強制することができますどのようにしかし、この方法は、Page_Load中に、以下の結果を実行していますか?

// The Method Mentioned 
public static class PageExtensions 
{ 
    public static void PrependTitle(this Page page, string newTitle) 
    { 
     page.Title = newTitle + " " + Global.TITLE_DELIMITER + " " + page.Title; 
    } 
} 

答えて

1

このメソッドがInitから呼び出されていることを確認したい場合は、呼び出しスタックを調べることができます。このような何か:

public static bool CalledFromInit() 
{ 
    //Grab the current Stack Trace and loop through each frame 
    foreach(var callFrame in new StackTrace().GetFrames()) 
    { 
     //Get the method in which the frame is executing 
     var method = callFrame.GetMethod(); 

     //Check if the method is Control.OnInit (or any other method you want to test for) 
     if(method.DeclaringType == typeof(Control) && method.Name == "OnInit") 
      //If so, return right away 
      return true; 
    } 

    //Otherwise, we didn't find the method in the callstack 
    return false; 
} 

その後、あなたのようにそれを使用します。

public static void PrependTitle(this Page page, string newTitle) 
{ 
    //If we aren't called from Init, do something 
    if (!CalledFromInit()) 
    { 
     //We could either return to silently ignore the problem 
     return; 

     //Or we could throw an exception to let the developer know they 
     // did something wrong 
     throw new ApplicationException("Invalid call to PrependTitle"); 
    } 

    //Do the normally processing 
    page.Title = newTitle + " " + Global.TITLE_DELIMITER + " " + page.Title; 
} 

しかし、私は、スタックトレースは、最も信頼性の高いものではないことを警告したいです。リリースでは、あなたのコードがコールスタックでそれを見ることができないように、Control.OnInitメソッドがインライン化されるようにコードを最適化することができます。このチェックは#if DEBUGブロックにラップすることができるので、開発中にのみ実行されます。あなたのユースケースに応じて、DEBUG中にこの問題を捕らえ、RELEASEでチェックするのを邪魔しないように十分な場合があります。しかし、それはあなた次第です。

別のオプション... Tommy Hinrichsの答えに基づいて、あなたのすべてのページが基本クラスから継承されていれば、より確実にそれを行うことができます。私はこのようなものをお勧めしたい:それは(正確に何をしたいのように聞こえる)PREINITとINITCOMPLETEの間で呼ばれていない限り、

public abstract class BasePage : Page 
{ 
    private bool _executingInit; 
    protected internal override void OnPreInit(EventArgs e) 
    { 
     _executingInit = true; 
     base.OnPreInit(e); 
    } 

    protected internal override void OnInitComplete(EventArgs e) 
    { 
     base.OnInitComplete(e); 
     _executingInit = true; 
    } 

    public void PrependTitle(string newTitle) 
    { 
     if (!_executingInit) 
      throw new ApplicationException("Invalid call to PrependTitle."); 

     Title = newTitle + " " + Global.TITLE_DELIMITER + " " + Title; 
    } 
} 

そうすれば、PrependTitleが例外をスローします。

最後のオプションとして、卑劣であり、反射を使用してControl.ControlStateプロパティにアクセスすることができます(これは、コントロール状態とは関係ないため、表示状態に似ています)。そのプロパティはコントロールのライフサイクルを追跡して追跡し、以下の値を持ちます:

internal enum ControlState 
{ 
    Constructed, 
    FrameworkInitialized, 
    ChildrenInitialized, 
    Initialized, 
    ViewStateLoaded, 
    Loaded, 
    PreRendered 
} 

Enumは内部であることがわかります。 Control.ControlStateプロパティもそうです。しかし、Reflectionでは、これを使用することができます。また、ページの外部にある拡張メソッドから使​​用することもできます。

希望の方法の1つがあなたのために働くでしょう!

+0

これは素晴らしい情報であり、私が意図したとおりに問題を解決します。ありがとう。 – roydukkey

0

あなたの最善の策は、イベントにメソッドを添付するHandlesキーワードを使用することが考えられます。

System.Web.UI.Pageのサブクラスを作成して、これを強制する必要があります。

0

問題はprependTitleメソッドにあると思われます。ページタイトルにテキストを置き換えないでください。

各マシュターページとページのpage_loadでPrependTitleメソッドを呼び出し、テキストをタイトルに追加するだけです。

+0

私はメソッドを追加しました。私はそれが問題だとは思わないが、私は間違っているかもしれない。 – roydukkey

2

これは次のように行うことができると思います。一般的な考え方は、密封されたとして、それへのアクセス権を持つべきもの

class AppsBasePage : Page 
{ 
    abstract void PrependTitle(string title); 
} 
class PageWithTitlePrepended : AppsBasePage 
{ 
    private void PrependTitle(string title) 
    { 
     Title = String.Format("{0} {1} {2}", newTitle, Global.TITLE_DELIMITER, Title); 
    } 
    protected sealed override void Page_Init(object sender, EventArgs e)  
    { 
     PrependTitle("This is a title") 
    } 
} 
class ActualPageInApp: PageWithTitlePrepended 
{ 
    override void Page_Load(object s, EventArgs e) 
    { 
     // can't access PrependTitle here 
    } 
} 

を宣言。これは、太字であなたの質問を解決するが、私はこのような状況は、とあなたの問題を引き起こしているものである確信していない、プライベートとしてメソッドを宣言しています特にPrependTitle。実際の問題を解決するためにもっとコードやコンテキストが必要だと思います。

+0

ハム...私はこれが唯一の解決策であることに驚いています。これは私が期待していたものではありません。また、PrependTitleメソッドに問題があるとは思わない。マスターからページへのPage_Initの実行と、ページからマスターへのPage_Loadのトリガーを理解しています。私は他の唯一の選択肢は、PrependTitleの中から現在のイベントを特定し、それに応じてそれに従うことだと思います。 – roydukkey

関連する問題