ASP.Net動態切換主題

ASP.Net動態切換主題

參考課堂講解改編,大部分借用了老師的原話

Step1:編寫一個主頁面

可以參考下面的佈局設計,在這裏的附件中提供了一個示例主界面,在MasterPage.Master中。
主界面佈局

Step 2:編寫主頁面的佈局

在aspx文件裏面編寫自己的佈局,並使用class來添加樣式。因爲使用主題,暫時不用引入CSS文件。參考文件TestMaster.aspx。

Step 3:編寫主題

  1. 每一個主題對應一個文件夾,主題的名字就是文件夾名字,主題文件夾裏放置 CSS 文件和其它資源文件。建議建立子文件夾,分類存放圖片、聲音、視頻等文件。
    在這裏插入圖片描述
  2. 每一個主題都有一個對應的 CSS 文件,該文件應當與主題名稱一致,並且放到主題文件夾下面(別放到子文件夾裏)。
  3. 在主題 CSS 文件裏給主頁面中各個 class 添加樣式。不同主題所面對的 class 是一樣的,只不過每一個 class 的樣式不一樣。

注:參考附件的主題編寫,自己可以自行編寫,設計不同的主題。

Step 4:添加動態切換主題的控件

  1. 在主頁面的合適位置,添加一個 DropDownList,用它來提供各個主題的選擇項。並且編寫它的事件處理方法。
  2. 請再移動到 selectTheme_SelectedIndexChanged 這裏,閱讀該方法的實現。
    幫助:鼠標右鍵點擊下面的 selectTheme_SelectedIndexChanged,選擇 查看代碼,即可跳轉。
    在這裏插入圖片描述

Step 5:編寫 DropDownList 的事件響應方法

根據 ASP.NET 頁面生命週期,當用戶改變 DropDownList 切換主題的時候,該方法被調用,然而此時已經錯過了能夠設置主題的時機:PreInit。所以,這裏只能將用戶選擇的主題先保存起來,再讓頁面重新加載一次。在下一次加載的時候,讀取保存起來的主題名稱,再切換主題。在這裏,我們選擇使用 Cookie 來保存用戶的選擇。
參考代碼:(這裏包含註釋,附件的代碼註釋少)
在這裏插入圖片描述

Step 6:創建一個自定義 Page 類

  1. 爲什麼需要這個類:
    設置主題 Theme 或者 StyleSheetTheme,都必須在 System.Web.UI.Page 的子類裏進行。但是主頁面的父類是 System.Web.UI.MasterPage,沒法設置。而在每一個我們編寫的頁面裏都去重複寫設置主題的代碼,顯然是重複勞動,跟主頁面一次搞定重複工作的思想也不一致。所以,可以藉助繼承,先在System.Web.UI.Page 下面寫一個新的頁面類,讓它去配合主頁面的工作,負責主題的動態切換。之後我們具體的aspx頁面,再繼承這個類就好了。

  2. 怎麼添加這個類?
    如果創建的是 ASP.NET 網站,那麼需要先創建一個 APP_Code 文件夾,在這個文件夾裏創建類。注意,APP_Code 是 ASP.NET 的特殊用途文件夾,名字固定,更改後失效。只有在這個文件夾裏創建類,才能夠在其它 cs 文件裏引用它。
    如果創建的是 Web App 工程,那麼可以在工程根目錄或者一個子文件夾裏創建一個類。但是特別注意,不能在APP_Code 文件夾裏創建類,會直接報錯。因爲 APP_Code 是專門爲 ASP.NET 網站預留的,在 Web App 工程裏不需要,而且還起反作用。最坑爹的是,VS 居然有提供新建 APP_Code 文件夾的選項,搞的和真的是的。

  3. 這個類要怎麼寫:
    (1)首先給它添加一個父類,必須是 System.Web.UI.Page;然後給它添加一個 public 無參構造函數。構造函數裏什麼也不要寫。注意,一定不要忘記 public 修飾,否則該構造函數就是 private 的,將沒法直接用 new 去實例化它,會報錯。
    在這裏插入圖片描述
    (2)之後,根據我們設置主題的方式,添加如下方法:
    1、如果要設置 Theme 屬性,讓主題後生效,那麼要添加 Page_PreInit 方法,響應 PreInit 事件。相關代碼 請閱讀下面的 Step 7A。

Step 7A:

(a). 這是一個事件處理方法,返回值必須是 void,兩個參數的類型分別是 object 和 EventArgs,且次序不能顛倒。這個方法的名字是 Page_PreInit,不能亂改。它是由 Page 的 AutoEventWireup屬性決定的。該方法不能是 private 修飾。
( b). 由於 PreInit 事件觸發得非常早,我們甚至連控件也看不到。在這裏唯一可以獲取的就是用戶的 http請求數據,而且還是原始數據。由於 Cookies 也是隨着 http 數據包一起發送的,所以之前寫入到Cookies 的主題名字還是在這裏能夠找到的。我們要做的就是取出之前存儲的主題名字,然後根據這個名字設置主題。注意,Cookies 數據是可以被 篡改的,一定要做充足的檢查。
參考代碼如下:
在這裏插入圖片描述

2、如果要設置 StyleSheetTheme 屬性,讓主題先生效,那麼要重寫 StyleSheetTheme 的 get 方法。相關代碼請閱讀下面的 Step 7B。
(a)StyleSheetTheme 屬性比較奇特,你會發現它無法被設置(沒有 set 方法)。所以正確的處理方式是重載它的 get 方法。注意,重載的時候,別忘了寫上 override 修飾符。重載完這個屬性之後,它會被自動調用,而且是在 PreInit 事件觸發時調用,我們不需要再寫一個 PreInit 事件的處理方法。
(b) 由於 PreInit 事件觸發得非常早,我們甚至連控件也看不到。在這裏唯一可以獲取的就是用戶的 http請求數據,而且還是原始數據。由於 Cookies 也是隨着 http 數據包一起發送的,所以之前寫入到Cookies 的主題名字還是在這裏能夠找到的。我們要做的就是取出之前存儲的主題名字,然後根據這個名字設置主題。注意,Cookies 數據是可以被篡改的,一定要做充足的檢查。
參考代碼:

 public override string StyleSheetTheme
    {
        get
        {
            // 這個方法的調用時機是在 PreInit 事件的處理方法裏首先判斷用戶的 Cookies 裏有沒有 themeName 這一項
            if (this.Request.Cookies["themeName"] != null)
            {
                // 如果 themeName 存在,那麼先取出來。注意,Cookies 裏面能夠找到themeName 這一項,不代表它的 Value 一定存在
                string themeName = this.Request.Cookies["themeName"].Value;
                // 進一步判斷取到的 themeName 是不是真的有數據
                if (!string.IsNullOrEmpty(themeName))
                {
                    // 如果字符串有內容,那還要再看看這個主題是不是真的存在,也就是檢查一下
                    // 對應的目錄是不是存在
                    // 這裏又要注意了(光 TM 注意了),"/App_Themes/" 是網站裏的虛擬目錄
                    // 需要先利用 Server.MapPath 把它轉換爲服務器操作系統的硬盤路徑,
                    // 這樣 System.IO 裏面的類才能找到對應的文件或者目錄。
                    string themePath = this.Server.MapPath("/App_Themes/" + themeName);
                    // 使用下面的方法,可以判斷目錄是否存在
                    if (System.IO.Directory.Exists(themePath))
                    {
                        // 到此爲止,這個主題纔算真能用
                        return themeName;
                    }
                }
            }

            // 上面進行了一系列檢查,只要有一項不通過,就會走到這裏。我們返回默認主題
            // 如果默認主題都不能用,啊.......還是去問問佛祖怎麼辦吧.......
            return "Blue";
            // 主題設置完畢了,此時嘗試更換主題,會發現有效果了,但是 DropDownList 的
            // 狀態不對,導致換不回去。那麼,該去看 MasterPage.master.cs 了。
        }
    }
  1. 最後在具體的aspx頁面,繼承這個類。
    在這裏插入圖片描述

Step 8:更新 DropDownList 的狀態

解決這個問題的關鍵是,判斷頁面是不是通過 PostBack 提交過來的。如果是首次打開, 那麼 DropDownList 的狀態只能根據 Cookies 設置,自然不會出錯。如果是用戶提交過 來的,DropDownList 可能被改變,此時 Cookies 裏的數據和提交過來的 DropDownList
狀態會不一致(Cookies 裏的數據是過時的)。此時要根據 DropDownList 來設置, 由於它自帶 ViewState,可以放手不管。
在MasterPage.master.cs 的Page_Load函數設置處理處理方法。

 sideInfo.Text += selectTheme.SelectedItem.Text + "<br/>";
  if (!IsPostBack)
        {
            # region UpdateSelection
            // 首先判斷用戶的 Cookies 裏有沒有 themeName 這一項
            if (this.Request.Cookies["themeName"] != null)
            {
                // 如果 themeName 存在,那麼先取出來。注意,Cookies 裏面能夠找到
                // themeName 這一項,不代表它的 Value 一定存在
                string themeName = this.Request.Cookies["themeName"].Value;
                // 進一步判斷取到的 themeName 是不是真的有數據
                if (!string.IsNullOrEmpty(themeName))
                {
                    // 由於 Cookies 數據不可靠,所以要先檢查一下用戶選的主題,在
                    // 列表裏有沒有。使用 DropDownList.Items.FindByText (這個
                    // 方法真夠隱蔽的,第二次寫居然沒找到......)
                    ListItem anItem = this.selectTheme.Items.FindByText(themeName);
                    if (anItem != null)
                    {
                        // 如果這個主題真的有,那麼可以設置了。注意,先把原來
                        // 選擇的選項清除掉,然後再設置。否則報錯,說同時選了多個
                        // (這個設計應該是微軟偷懶了,按理說,更變選擇,可以自動
                        //   清除原來的纔對,不就是一個事件嘛)
                        this.selectTheme.SelectedItem.Selected = false;
                        anItem.Selected = true;
                        sideInfo.Text += "Selection changed<br />";
                    }
                }
            }
            # endregion
        }
          sideInfo.Text += selectTheme.SelectedItem.Text + "<br/>";

注:到此爲止,動態切換主題就完成了。恭喜你走到了最後。最後的總結:如果感覺自己的思路沒有錯,但是結果卻非常不正常,此時請保持冷靜,去對照 ASP.NET 頁面生命週期,一步一步看看,是不是忽略了一些過程。

總結

以上大部分的註釋和說明採用老師的註釋,不是筆者寫,但是感覺老師寫的很不錯,因此發到網上,作爲參考,可以提供學習。步驟比較繁瑣,需要一步步的去做,若有疑問,可以留言,歡迎大家指出問題。

參考代碼的鏈接:
筆者編寫的代碼:https://pan.baidu.com/s/17hVPFrN09odusl4AEU3KTA
提取碼:8rlr

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章