﻿# 如何動態修改巢狀 MasterPage 的 MasterPageFile 屬性

我前天遇到一個 ASP.NET 開發的問題，我有一個網站，其中有些頁面套用了一層的 MasterPage、有些套用了兩層 MasterPage、有些套用了三層 MasterPage，這些套兩層以上 MasterPage 的 MasterPage 在第二層的地方都是套用第一層的 MasterPage，不過客戶突然說第一層的 MasterPage 必須要依據不同的網域名稱(Domain Name)而選用不同的 MasterPage，最後耗了我三個小時才解決這個問題。

MasterPage 的套用關係大致的示意如下：

```
MasterPageTop.master
   ->  MasterPageChannel1.master
       -> MasterPageChannel1_1.master
           -> ContentPage.aspx
```

而我的需求是要動態變更 MasterPageChannel1.master 裡的 MasterPageFile 屬性，讓 ContentPage.aspx 在顯示的時候將 MasterPageTop.master 改成 MasterPageTop2.master。

**問題與難點描述**

一般來說，若 ContentPage.aspx 只有套一層 MasterPage 的話，只要在該頁面的 Page\_PreInit 事件中指定 this.MasterPageFile 屬性即可動態變更該頁的 MasterPage，如下範例：

```
protected void Page_PreInit(object sender, EventArgs e)
{
    if (Request.Url.Host == "www.mydomain.com")
    {
        this.MasterPageFile = "~/MasterPageTop2.master";
    }
}
```

因為我有些頁面的 MasterPage 是套多層的，所以我就嘗試在 MasterPageChannel1.master 去設定 Page\_PreInit 事件設定相同的程式碼，不過好像沒效果，程式完全沒有執行，經查詢後才得知原來 MasterPage 裡面並無 Page\_PreInit 事件可以設定，最早的事件就是 OnInit 事件而已，所以從 MasterPage 去設定 MasterPageFile  是不可行的。

當下已經晚上九點，又還沒吃飯，感覺又好像是個無解的難題，不過總覺得不甘心就這樣放棄回家，一直拼到快 11 點才讓我寫出完美的解決方法。

**動態修改巢狀 MasterPage 的 MasterPageFile 屬性的解決方案**

既然從 MasterPage 去設定 MasterPageFile  是不可行的，那麼唯一個可能性就只有從內容頁面(ContentPage.aspx)下手了，因為所有前台 aspx 網頁都需要做出判斷，所以我寫了一個 BasePage，並覆寫(override) OnPreInit 事件，去動態修改頁面與每一層 MasterPage 中的 MasterPageFile 屬性（最多三層），而我的第一版 BasePage 寫成這樣：

```
/// <summary>
/// 讓所有前端的頁面繼承的共用 Page 類別
/// </summary>
public class FrontBasePage : Page
{
    protected override void OnPreInit(EventArgs e)
    {
        if (Request.Url.Host == "www.mydomain.com")
        {
            if (this.MasterPageFile == "/MasterPageTop.master")
                this.MasterPageFile = "~/MasterPageTop2.master"; 

            if (Master != null)
            {
                if (Master.MasterPageFile == "/MasterPageTop.master")
                    Master.MasterPageFile = "~/MasterPageTop2.master"; 

                if (Master.Master != null)
                {
                    if (Master.Master.MasterPageFile == "/MasterPageTop.master")
                        Master.Master.MasterPageFile = "~/MasterPageTop2.master"; 

                    if (Master.Master.Master != null)
                    {
                        if (Master.Master.Master.MasterPageFile == "/MasterPageTop.master")
                            Master.Master.Master.MasterPageFile = "~/MasterPageTop2.master";
                    }
                }
            }
        }
        // 若有在內容頁面中有定義 Page_PreInit 事件的話會先在 base.OnPreInit(e) 執行！
        base.OnPreInit(e); 
    }
}
```

其實這樣寫已經可以了，不過在我的頁面中卻無法正確的替換掉正確的 MasterPageTop2.master，原因就出在 base.OnPreInit(e); 這行。

若在內容頁面(Content Page)中有定義 Page\_PreInit 事件的話會，真正呼叫這個事件執行的地方是在 base.OnPreInit(e) 內，而好巧不巧的我其中有一頁的 Page\_PreInit 事件剛好也有寫到指定 MasterPageFile 屬性的程式，導致我在 FrontBasePage 所做出的設定到了 base.OnPreInit(e) 又被改回來了。

所以我最後我將 base.OnPreInit(e) 移到上面後，所有問題就都修復了！修改後的程式碼如下：

```
/// <summary>
/// 讓所有前端的頁面繼承的共用 Page 類別
/// </summary>
public class FrontBasePage : Page
{
    protected override void OnPreInit(EventArgs e)
    {
        // 若有在內容頁面中有定義 Page_PreInit 事件的話會先在 base.OnPreInit(e) 執行！
        base.OnPreInit(e); 

        if (Request.Url.Host == "www.mydomain.com")
        {
            if (this.MasterPageFile == "/MasterPageTop.master")
                this.MasterPageFile = "~/MasterPageTop2.master"; 

            if (Master != null)
            {
                if (Master.MasterPageFile == "/MasterPageTop.master")
                    Master.MasterPageFile = "~/MasterPageTop2.master"; 

                if (Master.Master != null)
                {
                    if (Master.Master.MasterPageFile == "/MasterPageTop.master")
                        Master.Master.MasterPageFile = "~/MasterPageTop2.master"; 

                    if (Master.Master.Master != null)
                    {
                        if (Master.Master.Master.MasterPageFile == "/MasterPageTop.master")
                            Master.Master.Master.MasterPageFile = "~/MasterPageTop2.master";
                    }
                }
            }
        }
    }
}
```

**參考連結**

-   [Nested Master Pages](http://www.asp.net/learn/master-pages/tutorial-10-cs.aspx)
