天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

asp.net Web站點(diǎn)風(fēng)格切換的實(shí)現(xiàn)

Web站點(diǎn)風(fēng)格切換的實(shí)現(xiàn)

引言

Web站點(diǎn)的風(fēng)格切換是很常見(jiàn)、也很受大家歡迎的功能,比如大家熟知的博客園就提供了幾十款風(fēng)格模板供大家選擇。在ASP.NET中,我們可以通過(guò)模板頁(yè)master page和主題theme來(lái)實(shí)現(xiàn)網(wǎng)站的風(fēng)格切換,但是.NET提供的默認(rèn)設(shè)置不夠強(qiáng)大和靈活。本文將向大家介紹如何在.NET提供的方法上進(jìn)行改進(jìn)和擴(kuò)展,以提供更加強(qiáng)大的網(wǎng)站風(fēng)格切換功能。

效果預(yù)覽:http://www.tracefact.NET/Demo/StyleSetting/default.ASPx

NOTE:本文將master page稱(chēng)為模板(有的書(shū)上叫母版),將theme稱(chēng)為主題。

網(wǎng)頁(yè)的結(jié)構(gòu) 和 模板、主題配置的局限

靜態(tài)網(wǎng)頁(yè)的結(jié)構(gòu)

網(wǎng)站的風(fēng)格的切換,說(shuō)白了,實(shí)際上就是對(duì)頁(yè)面進(jìn)行分解和重組。所以在進(jìn)行之前,我們先簡(jiǎn)單回顧看一下頁(yè)面究竟有哪些組成部分可以供我們分解,分清楚哪些是可變的、哪些是不變的,進(jìn)行后繼的工作才會(huì)容易得多。現(xiàn)在我們先暫時(shí)脫離服務(wù)器端,看一下一個(gè)靜態(tài)的.htm頁(yè)面由哪幾部分組成:

結(jié)構(gòu)(有語(yǔ)義的XHTML):這部分由XHTML標(biāo)記組成,應(yīng)該注意,這里使用“有語(yǔ)義”三個(gè)字作為修飾。XHTML的職責(zé)是告訴“這里是什么”,而不是告訴“這里應(yīng)該如何顯示”。盡管瀏覽器對(duì)于幾乎每個(gè)XHTML的標(biāo)記都賦予了某種內(nèi)置的樣式控制,但是XHTML的本意只是規(guī)范文檔的結(jié)構(gòu)。比如h1表示為標(biāo)題,p表示為段落。而不是為了這個(gè)字顯示的更大一些才去使用h1。

表現(xiàn)和布局(CSS):CSS用來(lái)控制頁(yè)面的顯示及布局。在Web標(biāo)準(zhǔn)的概念普及以前,我想大多人都是表格套表格來(lái)布局的,現(xiàn)在基本都在使用CSS了,這里沒(méi)有太多好說(shuō)的。

行為(Javascript):靜態(tài)網(wǎng)頁(yè)也可以添加一些交互的行為,這些行為由Javascript來(lái)完成。我們時(shí)常會(huì)把onclick="alert('hello')"這樣的代碼嵌入到XHTML標(biāo)記中,比如一個(gè)Input標(biāo)記上;一些結(jié)構(gòu)、行為分離的狂熱人士則主張將行為與結(jié)構(gòu)(XHTML)分離,他們不會(huì)將Javascript代碼寫(xiě)到<body>之間,而全部寫(xiě)在了head中,或者是body下面,使用 window.onload=function(){ // …} 這種形式。有個(gè)極力主張這種做法的人(Peter-Paul Koch)寫(xiě)了本書(shū)叫《ppk on Javascript》。

好了,大概了解了這些,我們看下.NET中如何將這三者分離,以及它的一些限制:

.NET對(duì)頁(yè)面結(jié)構(gòu)的分離

我到現(xiàn)在都覺(jué)得 行為與結(jié)構(gòu) 完全分離的概念太前衛(wèi)了,另外它也不影響對(duì)網(wǎng)站的風(fēng)格設(shè)置,所以我們這里不討論它。

我們先看一下結(jié)構(gòu):現(xiàn)在我們將思維向服務(wù)器端靠攏一下,很快會(huì)發(fā)現(xiàn)上面的結(jié)構(gòu)部分仍需要再細(xì)分一次,就是XHTML標(biāo)記和標(biāo)記中的內(nèi)容(網(wǎng)頁(yè)內(nèi)容)分離。XHTML標(biāo)記屬于變化的部分,不同的風(fēng)格可能會(huì)需要不同的XHTML結(jié)構(gòu),而對(duì)于各個(gè)風(fēng)格,它所顯示的內(nèi)容顯然是一樣的。想要得到這樣的效果,我們可以使用Master Page模板頁(yè)。由Master Page模板頁(yè)對(duì)應(yīng)XHTML結(jié)構(gòu)(變化部分),由Page頁(yè)面對(duì)應(yīng)于XHTML頁(yè)面的內(nèi)容(不變部分),即是一個(gè)Page可以設(shè)置為不同的Master Page以達(dá)到不同的樣式(look and feel)。

NOTE:這里在說(shuō)一下CSS,如果你的CSS水平足夠強(qiáng),XHTML的代碼寫(xiě)得足夠好,那么你無(wú)需搞得這么復(fù)雜,僅僅使用CSS就可以實(shí)現(xiàn)換膚了。www.csszengarden.com有這樣的一個(gè)項(xiàng)目提供給全世界的人作為實(shí)踐,它提供一套統(tǒng)一的XHTML代碼,其他人則自己編寫(xiě)CSS來(lái)對(duì)這個(gè)XHTML代碼進(jìn)行樣式化,結(jié)果是百花齊放,一模一樣的XHTML實(shí)現(xiàn)了風(fēng)格迥異的頁(yè)面設(shè)計(jì)。

現(xiàn)在在看一下表現(xiàn)部分,表現(xiàn)層分為全局式的CSS以及基于控件的皮膚Skin,這些都可以交由主題Theme來(lái)完成。

.NET 設(shè)置上的局限

看到這里,你可能覺(jué)得不用往下看了,使用Master Page和Theme誰(shuí)不會(huì)啊。現(xiàn)在我們就討論下.NET 中Master Page 和 Theme 的局限:

  • 大家知道,我們可以在 Web.config中的System.Web結(jié)點(diǎn)下的pages結(jié)點(diǎn)中添加Theme和masterPageFile屬性來(lái)對(duì)網(wǎng)站進(jìn)行設(shè)置。但是它提供了一個(gè)全局性的配置,就是對(duì)于整個(gè)站點(diǎn)的所有頁(yè)面,都將使用這個(gè)Master Page。而有時(shí)候我們希望能夠每個(gè)頁(yè)面不相同,這里就無(wú)法實(shí)現(xiàn)了。雖然我們可以通過(guò)使用location結(jié)點(diǎn)來(lái)為各個(gè)頁(yè)面進(jìn)行單獨(dú)設(shè)置,但是顯然太麻煩了。
  • 我們希望每個(gè)風(fēng)格都有個(gè)名字,比如說(shuō)“默認(rèn)風(fēng)格”、“春意盎然”。
  • 我們希望用戶(hù)可以選擇風(fēng)格,而不是像博客園這樣由博主設(shè)置風(fēng)格。

實(shí)現(xiàn)網(wǎng)站的風(fēng)格切換

自定義風(fēng)格配置

有了思路后我們就來(lái)一步步地實(shí)現(xiàn)它,我們希望可以對(duì)風(fēng)格進(jìn)行簡(jiǎn)單的設(shè)置,我們應(yīng)該先明確需要設(shè)置的內(nèi)容:我們都有哪些風(fēng)格、當(dāng)前使用的風(fēng)格是什么、每個(gè)風(fēng)格使用了什么主題、哪個(gè)頁(yè)面對(duì)應(yīng)哪個(gè)模板。了解了這些之后,我們可以寫(xiě)下這樣的結(jié)點(diǎn)配置來(lái):

<!-- MasterPage的 Path為 masterRoot + theme + master -->
<!-- 不為Default設(shè)置masterPage,
     使用Default風(fēng)格時(shí)會(huì)使用創(chuàng)建頁(yè)面時(shí)所選擇的Master Page -->
<styleTemplates default="默認(rèn)風(fēng)格" masterRoot="~/MasterPage">
     <style name="默認(rèn)風(fēng)格" theme="Default" ></style>
     <style name="春意盎然" theme="Spring" >
          <masterPages>
               <page path="/website/default.ASPx" master="Default.master" />
               <!--<page path="/other.ASPx" master="Default.master" />-->
               <page path="/default.ASPx" master="Default.master" />
          </masterPages>
     </style>
</styleTemplates>

styleTemplates是風(fēng)格設(shè)置的根節(jié)點(diǎn),default是默認(rèn)的風(fēng)格名稱(chēng);masterRoot是指模板頁(yè)的根目錄的地址;style結(jié)點(diǎn)是各個(gè)風(fēng)格的名稱(chēng),以及其所使用的主題的名稱(chēng);style結(jié)點(diǎn)下的masterPages結(jié)點(diǎn)組包含此風(fēng)格所使用的模板的信息;其中Page子結(jié)點(diǎn)對(duì)應(yīng)每個(gè)獨(dú)立的頁(yè)面,path屬性記錄的是頁(yè)面的路徑,master屬性是每個(gè)頁(yè)面對(duì)應(yīng)的模板的路徑。

page結(jié)點(diǎn)的master屬性沒(méi)有給出模板的全路徑,這么做一個(gè)是為了使目錄結(jié)構(gòu)更一目了然,還有就是不想master屬性的內(nèi)容變得很長(zhǎng),所以需要在程序中指定頁(yè)面的模板的路徑為 masterRoot + Theme + masterPage名稱(chēng)。這樣在模板的根目錄下,必須建立與主題同名的目錄,然后將模板位于該目錄下。

在創(chuàng)建頁(yè)面時(shí),我們需要要選擇一個(gè)模板。注意到這一點(diǎn)非常重要,因?yàn)檫@個(gè)模板實(shí)際上是該頁(yè)面的默認(rèn)模板。當(dāng)我們?cè)赪eb.config中將相應(yīng)風(fēng)格的page結(jié)點(diǎn)留空時(shí)(沒(méi)有對(duì)此頁(yè)面設(shè)置模板),那么就會(huì)應(yīng)用這個(gè)模板。所以在Web.Config中定義風(fēng)格的模板,只是覆蓋了這個(gè)我們?cè)趧?chuàng)建頁(yè)面時(shí)選擇的模板。由此,我們只用定義一套完整的Master Page模板頁(yè),供每個(gè)頁(yè)面在創(chuàng)建時(shí)選擇。而Web.config風(fēng)格結(jié)點(diǎn)下設(shè)置的master page,實(shí)際上僅僅是動(dòng)態(tài)地覆蓋這些模板。

以上面的配置為例:當(dāng)我們將 “春意盎然” 下的第二個(gè) page 結(jié)點(diǎn)注釋掉時(shí),它會(huì)應(yīng)用創(chuàng)建頁(yè)面時(shí)所選擇的模板。“默認(rèn)風(fēng)格”下面沒(méi)有設(shè)置任何的 page 結(jié)點(diǎn),所以對(duì)于該風(fēng)格的每個(gè)頁(yè)面,都會(huì)應(yīng)用創(chuàng)建頁(yè)面時(shí)所選擇的模板。

如果你希望僅使用Css來(lái)?yè)Q膚,你可以使用也可以不使用Master Page,那么在Web.Config中可以像下面這樣設(shè)置:

<styleTemplates default="默認(rèn)風(fēng)格" masterRoot="">
     <style name="默認(rèn)風(fēng)格" theme="Default" ></style>
     <style name="春意盎然" theme="Spring" ></style>
     <style name="秋高氣爽" theme="Autumn" ></style>
</styleTemplates>

對(duì)于上面使用Master Page時(shí)的設(shè)置,站點(diǎn)的目錄結(jié)構(gòu)如下所示:

可以看到模板頁(yè)的根目錄下包含了目錄Default、Spring與主題名稱(chēng)相同(必須)。之后我們要編寫(xiě)結(jié)點(diǎn)處理程序,如何編寫(xiě)自定義結(jié)點(diǎn)處理程序,我在《.NET 自定義應(yīng)用程序配置》一文中已經(jīng)詳細(xì)的討論了,所以這里我們直接看實(shí)現(xiàn),在AppCode目錄中新建一個(gè)文件StyleTemplateConfigHandler.cs:

public class StyleTemplateConfigHandler : IConfigurationSectionHandler
{
    public object Create(object parent, object configContext, XmlNode section) {
       return new StyleTemplateConfiguration(section);
    }
}

// 映射 styleTemplates 結(jié)點(diǎn)的實(shí)體類(lèi)
public class StyleTemplateConfiguration {

    private XmlNode node;           // styleTemplates 結(jié)點(diǎn)
    private string defaultTheme;    // 默認(rèn)的主題名稱(chēng)
    private string defaultStyle;    // 站點(diǎn)默認(rèn)風(fēng)格名稱(chēng)
    private HttpContext context;
    private Dictionary<string,string> styleDic; // Key: 風(fēng)格名稱(chēng);Value: 主題名稱(chēng)


    public StyleTemplateConfiguration(XmlNode node) {
       this.node = node;
       context = HttpContext.Current;
       styleDic = new Dictionary<string, string>();

       // 獲取所有style結(jié)點(diǎn)的 name屬性 和 theme屬性
       XmlNodeList styleList = node.SelectNodes("style");
       foreach (XmlNode style in styleList) {
           styleDic[style.Attributes["name"].Value] = style.Attributes["theme"].Value;
       }

       // 獲取 站點(diǎn)默認(rèn)風(fēng)格 名稱(chēng)
       defaultStyle = node.Attributes["default"].Value;

       // 根據(jù) 風(fēng)格名稱(chēng) 獲取主題
       defaultTheme = styleDic[defaultStyle];
    }

    // 獲取所有風(fēng)格名稱(chēng)
    public ICollection<String> StyleNames {
       get {
           return styleDic.Keys;
       }
    }

    // 根據(jù)風(fēng)格名稱(chēng)獲取主題名稱(chēng)
    public string GetTheme(string styleName) {
       return styleDic[styleName];
    }

    // 設(shè)置、獲取 站點(diǎn)默認(rèn)風(fēng)格
    public string DefaultStyle{
       get {
           return defaultStyle;
       }
       set { // 更改Web.Config中的默認(rèn)風(fēng)格,一般為站長(zhǎng)才可以使用
           XmlDocument doc = new XmlDocument();
           doc.Load(context.Server.MapPath(@"~/web.config"));
           XmlNode root = doc.DocumentElement;
           XmlNode styleTemp = root.SelectSingleNode("styleTemplates");

           styleTemp.Attributes["default"].Value = value;
           doc.Save(context.Server.MapPath(@"~/web.config"));
       }
    }

    // 獲取默認(rèn)主題名稱(chēng)
    public string DefaultTheme {
       get { return defaultTheme;   }
    }

    // 根據(jù)頁(yè)面路徑獲取其對(duì)應(yīng)的 masterPage 的路徑
    public string GetMasterPage(string userTheme){

       // 獲取當(dāng)前頁(yè)面路徑
       string pagePath = context.Request.Path;

       // 用于定位page結(jié)點(diǎn)的 XPath
       string xpath = "style[@theme='" + userTheme + "']" + "/masterPages/page[@path='" + pagePath.ToLower() + "']";

       // 獲取與path屬性相匹配的page結(jié)點(diǎn)
       XmlNode pageNode = node.SelectSingleNode(xpath);

       string master;
       if (pageNode != null) {
           // 獲取page結(jié)點(diǎn)的 master屬性的值
           master = pageNode.Attributes["master"].Value;
           return prepareMasterPath(master, userTheme);
       } else
           return null;
    }

    // 獲取 Master Page 的路徑
    // MasterPagePath = 跟路徑 + Theme路徑 + 模板路徑
    private string prepareMasterPath(string masterPath, string userTheme) {
       string path;

       if (node.Attributes["masterRoot"] != null)
           path = node.Attributes["masterRoot"].Value + "/" + userTheme + "/" + masterPath;
       else {
           if (userTheme != null) {
              path = "~/" + userTheme + "/" + masterPath;
           } else {
              path = "~/" + masterPath;
           }
       }
       return path;
    }
}

這個(gè)類(lèi)提供了一些簡(jiǎn)單的對(duì)XmlNode的操作,對(duì)styleTemplates結(jié)點(diǎn)進(jìn)行了映射,這里需要明確兩個(gè)概念:默認(rèn)風(fēng)格 和 用戶(hù)風(fēng)格:

  • 默認(rèn)風(fēng)格,指的是站點(diǎn)管理員 或者 博主設(shè)置的風(fēng)格,也就是Web.Config 中styleTemplates結(jié)點(diǎn)的Default屬性。
  • 用戶(hù)風(fēng)格,用戶(hù)設(shè)置的風(fēng)格,頁(yè)面的實(shí)際顯示是根據(jù)用戶(hù)風(fēng)格而 不是默認(rèn)風(fēng)格。當(dāng)用戶(hù)沒(méi)有設(shè)置風(fēng)格時(shí),才顯示默認(rèn)風(fēng)格。

很顯然,這個(gè)類(lèi)處理的所有的均是默認(rèn)風(fēng)格,我們來(lái)看一下它的幾個(gè)主要方法和屬性:

// 獲取所有風(fēng)格名稱(chēng)
public ICollection<String> StyleNames { get {;}   }

// 根據(jù)風(fēng)格名稱(chēng)獲取主題名稱(chēng)
public string GetTheme(string styleName) {}

// 設(shè)置、獲取 站點(diǎn)默認(rèn)風(fēng)格
public string DefaultStyle{}

// 獲取默認(rèn)主題名稱(chēng)
public string DefaultTheme { }

// 根據(jù)頁(yè)面路徑獲取其對(duì)應(yīng)的 masterPage 的路徑
public string GetMasterPage(string userTheme){}

IUserStyleStrategy,獲取、設(shè)置用戶(hù)風(fēng)格

在繼續(xù)進(jìn)行之前,我們來(lái)考慮這樣一個(gè)問(wèn)題:因?yàn)槲覀円鶕?jù)用戶(hù)選擇的風(fēng)格來(lái)動(dòng)態(tài)地為頁(yè)面加載主題和模板,那么用戶(hù)信息(用戶(hù)選擇了什么風(fēng)格)應(yīng)該保存在哪里,從哪里獲得呢?我們有很多的選擇:可以使用Session、可以使用Cookie,還可以保存到數(shù)據(jù)庫(kù)中。此時(shí)最好將這部分抽象出來(lái),以便日后為不同的方法提供實(shí)現(xiàn)。我們定義一個(gè)接口 IUserStyleStrategy,它用來(lái)定義如何獲取、設(shè)置用戶(hù)風(fēng)格,在AppCode中新建文件IUserStyleStragety.cs:

public interface IUserStyleStrategy{
    void ResetUserStyle(string styleName);  // 重新設(shè)置用戶(hù)風(fēng)格
    string GetUserStyle();                     // 獲取用戶(hù)風(fēng)格
}

然后我在這里提供了一個(gè)基于Cookie的默認(rèn)實(shí)現(xiàn):

// 默認(rèn)風(fēng)格設(shè)置方法:使用Cookie記錄
public class DefaultStyleStrategy : IUserStyleStrategy {

    private string cookieName;          // cookie名稱(chēng)
    private HttpContext context;

    public DefaultStyleStrategy(string cookieName){
       this.cookieName = cookieName;
       context = HttpContext.Current;
    }

    // 重新設(shè)置用戶(hù)風(fēng)格名稱(chēng)
    public void ResetUserStyle(string styleName) {
       HttpCookie cookie;
       if(context.Request.Cookies[cookieName]!=null)
           cookie = context.Request.Cookies[cookieName];
       else
           cookie = new HttpCookie(cookieName);

       cookie.Value = context.Server.UrlEncode(styleName);
       cookie.Expires = DateTime.Now.AddHours(2); // 設(shè)置Cookie過(guò)期時(shí)間

       context.Response.Cookies.Add(cookie);

       // 因?yàn)轱L(fēng)格(master page和theme)的動(dòng)態(tài)設(shè)置只能在 PreInit 事件中
       // 而B(niǎo)utton的Click事件在PreInit事件之后,所以需要Redirect才可以生效
       context.Response.Redirect(context.Request.Url.PathAndQuery);
    }

    // 獲取用戶(hù)自己設(shè)置的風(fēng)格名稱(chēng)
    public string GetUserStyle() {     
       if (context.Request.Cookies[cookieName] != null) {
           string value = context.Request.Cookies[cookieName].Value;
           value = context.Server.UrlDecode(value);   // 避免出現(xiàn)中文亂碼
           return value;
       } else
           return null;
    }
}

如果日后你需要將信息保存在數(shù)據(jù)庫(kù)中,那么你只要重新實(shí)現(xiàn)一下這個(gè)接口就可以了:

// 如果將用戶(hù)風(fēng)格設(shè)置存儲(chǔ)到了數(shù)據(jù)庫(kù)中,可以實(shí)現(xiàn)這個(gè)接口
public class SqlStyleStrategy : IUserStyleStrategy {

    private int userId;          // 用戶(hù)Id

    public SqlStyleStrategy(int userId){
       this.userId = userId;
       // ...
    }

    public void ResetUserStyle(string styleName) {
       throw new NotImplementedException();
    }

    public string GetUserStyle() {
       throw new NotImplementedException();
    }
}

PageBase 類(lèi):繼承自Page的基類(lèi)

因?yàn)樗械捻?yè)面都要運(yùn)行這樣的一個(gè)邏輯:判斷用戶(hù)是否有設(shè)置風(fēng)格,如果沒(méi)有,使用Web.Config中設(shè)置的默認(rèn)風(fēng)格;如果設(shè)置了,使用用戶(hù)風(fēng)格。最后動(dòng)態(tài)地給Page類(lèi)的Theme屬性和MasterPageFile屬性賦值。

那么我們可以定一個(gè)基類(lèi),在這個(gè)基類(lèi)中去做這件事,然后讓所有的頁(yè)面繼承這個(gè)基類(lèi);又因?yàn)轫?yè)面是一定要繼承自System.Web.UI.Page類(lèi)的,所以這個(gè)基類(lèi)也必須繼承自System.Web.UI.Page。現(xiàn)在在AppCode中再建一個(gè)文件 PageBase.cs:

// 供所有基類(lèi)繼承
public class PageBase : Page
{
    protected StyleTemplateConfiguration styleConfig;
    protected string userStyle;         // 用戶(hù)設(shè)置的風(fēng)格
    protected string userTheme;         // 用戶(hù)設(shè)置的主題
    protected IUserStyleStrategy userStrategy; // 使用何種算法來(lái)獲得用戶(hù)自定義的信息
          
    protected override void OnPreInit(EventArgs e) {
       base.OnPreInit(e);

       // 這里會(huì)被緩存只在第一次時(shí)調(diào)用有用
       this.styleConfig = (StyleTemplateConfiguration)ConfigurationManager.GetSection("styleTemplates");

       // 當(dāng)你實(shí)現(xiàn)了自己的 Strategy時(shí)只需要更改這里就可以了
       // 更好的辦法是將Stragey的類(lèi)型保存在Web.config中,
       // 然后使用反射來(lái)動(dòng)態(tài)創(chuàng)建
       userStrategy = new DefaultStyleStrategy("userStyle");

       // 獲取用戶(hù)風(fēng)格
       userStyle = userStrategy.GetUserStyle();

       // 如果用戶(hù)沒(méi)有設(shè)置風(fēng)格,使用默認(rèn)風(fēng)格
       if (String.IsNullOrEmpty(userStyle)) {
           userStyle = styleConfig.DefaultStyle;
           userTheme = styleConfig.DefaultTheme;
       } else {
           // 根據(jù)用戶(hù)設(shè)置的風(fēng)格 獲取 主題名稱(chēng)
           userTheme = styleConfig.GetTheme(userStyle);
       }

       // 根據(jù)當(dāng)前頁(yè)獲取MasterPage的路徑
       string masterPagePath = styleConfig.GetMasterPage(userTheme);

       // 設(shè)置當(dāng)前頁(yè)的MasterPage
       if (masterPagePath != null)
           this.MasterPageFile = masterPagePath;

       this.Theme = userTheme;      // 設(shè)置當(dāng)前頁(yè)的主題
    }
}

這里需要注意:

  1. ConfigurationManager.GetSection()方法只會(huì)調(diào)用一次,然后會(huì)將結(jié)果進(jìn)行緩存;只要Web.Config不做修改,以后不管是Request還是PostBack都不會(huì)再重新生成StyleTemplateConfig的類(lèi)型實(shí)例,而會(huì)從緩存中讀取。我在《.NET 自定義應(yīng)用程序配置》中忘記說(shuō)了。
  2. userStrategy = new DefaultStyleStrategy("userStyle");這里可以將IUserStyleStrategy的類(lèi)型信息保存在Web.config中,然后使用反射動(dòng)態(tài)創(chuàng)建。具體方法依然參見(jiàn)《.NET 自定義應(yīng)用程序配置》。
  3. 如果想動(dòng)態(tài)地為頁(yè)面設(shè)置主題和模板,代碼必須寫(xiě)在PreInit事件中。參見(jiàn)《ASP.NET Page Life Cycle Overview》。

效果預(yù)覽

因?yàn)檫@只是一個(gè)范例程序,我主要是表達(dá)實(shí)現(xiàn)的思路,而不是代碼的編寫(xiě),所以省略了很多諸如結(jié)點(diǎn)屬性是否為空之類(lèi)的判斷。下面的測(cè)試僅僅在Web.Config中的配置正確時(shí)。在站點(diǎn)下新建一個(gè)頁(yè)面,比如Default.ASPx,注意創(chuàng)建一個(gè)模板頁(yè),因?yàn)檫@里設(shè)置的是會(huì)被覆蓋的,所以無(wú)所謂選擇哪個(gè)模板。

添加App_Theme下創(chuàng)建目錄Default、Spring,新建一個(gè)目錄MasterPage,在下面創(chuàng)建目錄Default、Spring,然后添加一些文件(這就不用我說(shuō)了吧)。在頁(yè)面上添加一個(gè)DropDonwList,一個(gè)Button,當(dāng)我們選擇要顯示的模板時(shí),會(huì)進(jìn)行相應(yīng)的切換,編寫(xiě)后置代碼:

protected void Page_Load(object sender, EventArgs e) {

    if (!IsPostBack) {
       ltrStyleName.Text = userStyle;

       foreach (string styleName in styleConfig.StyleNames) {
           ListItem item = new ListItem(styleName);
           if (string.Compare(styleName, userStyle) == 0)
              item.Selected = true;
           ddlStyles.Items.Add(item);
       }
    }
}

// 更換風(fēng)格
protected void Button1_Click(object sender, EventArgs e) {
    string styleName = ddlStyles.SelectedValue;
    userStrategy.ResetUserStyle(styleName); // 委托給userStragety去處理
}

之后你可以看到下面的畫(huà)面:

可以通過(guò)下面這個(gè)連接來(lái)看實(shí)際的效果,注意到:在這里我讓 Default.ASPx 和 Other.ASPx 使用了同一個(gè)模板,你也可以設(shè)置它們使用不同的模板。

http://www.tracefact.NET/Demo/StyleSetting/default.ASPx

總結(jié)

在這篇文章中,我簡(jiǎn)單地向大家介紹了實(shí)現(xiàn)網(wǎng)站風(fēng)格切換的一個(gè)思路。

我們首先復(fù)習(xí)了網(wǎng)頁(yè)的結(jié)構(gòu),了解了.NET默認(rèn)配置的不足。接著分三個(gè)步驟實(shí)現(xiàn)了網(wǎng)站的風(fēng)格切換:處理配置結(jié)點(diǎn)的程序、獲取用戶(hù)風(fēng)格的方法、以及通過(guò)基類(lèi)繼承來(lái)為各個(gè)頁(yè)面設(shè)置風(fēng)格。最后我們通過(guò)簡(jiǎn)單的兩個(gè)頁(yè)面進(jìn)行了下測(cè)試和預(yù)覽。

感謝閱讀,希望這篇文章能給你帶來(lái)幫助!

AspNet技術(shù)asp.net Web站點(diǎn)風(fēng)格切換的實(shí)現(xiàn),轉(zhuǎn)載需保留來(lái)源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 越南美女内射BBWXZ | 芒果影院网站在线观看 | 秘密影院久久综合亚洲综合 | 乱码午夜-极品国产内射 | 色窝窝亚洲AV在线观看 | 小SAO货水真多把你CAO烂 | 麻豆狠色伊人亚洲综合网站 | 天天日免费观看视频一1 | 2021久久99国产熟女人妻 | 天美传媒在线完整免费观看网站 | 在线观看中文字幕国产 | 亚洲伊人久久一次 | 国产成人午夜精品免费视频 | 日本69色视频在线观看 | 女人张腿让男人桶免费 | 欧美牲交视频免费观看K8经典 | gv肉片视频免费观看 | 国产色婷婷精品人妻蜜桃成熟 | 无敌在线视频观看免费 | 久久亚洲精品专区蓝色区 | 日本女人bbb| 校园男男高h小黄文 | 欧美一区二区激情视频 | 手机看片一区二区 | 国产喷水1区2区3区咪咪爱AV | 国产高清免费观看 | 欧美一级久久久久久久久大 | 特大黑人娇小亚洲女mp4 | 灰原哀被啪漫画禁漫 | 国产精品久久久久久亚洲影视 | 在线看片韩国免费人成视频 | 美国ZOOM动物在线观看 | 色偷偷91综合久久噜噜 | 少妇无套内谢久久久久 | 欧美一夜爽爽爽爽爽爽 | 精品视频久久久久 | 老版香蕉版下载 | 多肉np一女多男高h爽文现代 | 永久adc视频年龄确认 | 免费观看高清黄页网址大全 | 老阿姨才是最有味的一区二区 |