2011年9月22日

ASP.NET MVC - ASP.NET MVC 4 View Switcher

2012/02/25更新

不知道大家有沒有用行動裝置上過網,有一些知名的網站都會針對行動裝置來設計適合行動裝置的網頁設計,但有的時候,因為網頁變了,所以我常常找不到我想要的功能…,所以這次我們要講的是如何自動搜尋想要的功能嗎?當然不可能,這個主題要講的是"將行動裝置的頁面切換成原本的頁面",也就是View Switcher功能。

首先我們先看一下效果,產生的行動裝置頁面,紅色框框就是我常常用到的功能,用來切回原本桌面端的頁面功能。

image

感覺很Cool吧,現在我們看看在ASP.NET MVC 4該怎麼寫。

首先,我們要先準備一個_ViewSwitcher這個View。_ViewSwitcher的程式碼了,如下,首先第一行會判斷是否為Mobile裝置,如果是的話,才會顯示切換的連結,如果是Desktop的話,就不會顯示連結了。

假設我們這邊一開始是使用Mobile裝置,進入第二個if,接下來,我們會使用GetOverriddenBrowser()方法來取得HttpBrowserCapabilitiesBase的實體,然後使用IsMobileDevice來判斷是否為Mobile裝置,如果是的話,就會顯示切換到Desktop頁面的連結,如果不是的話,就會切換到Mobile的連結。

@if (Request.Browser.IsMobileDevice && Request.HttpMethod == "GET")
{
    <div class="view-switcher ui-bar-a">
        @*這裡使用GetOverriddenBrowser來取得HttpBrowserCapabilitiesBase實體,
        並且使用IsMobileDevice來判斷是否為Mobile裝置*@
        @if (ViewContext.HttpContext.GetOverriddenBrowser().IsMobileDevice)
        {
            @*是Mobile裝置的話執行這段*@
            @: Displaying mobile view
            @*切換頁面,並且將要傳入Controller的mobile屬性設為false,
              這樣Controller才會切換成Desktop的頁面,
              另外PathAndQuery如同其名,就是取得網址後面的路徑與參數。
            *@
            @Html.ActionLink("Desktop view", "SwitchView", "ViewSwitcher"
                , new { mobile = false, returnUrl = Request.Url.PathAndQuery }
                , new { rel = "external" })
        } 
        else 
        {
            @: Displaying desktop view
            @Html.ActionLink("Mobile view", "SwitchView", "ViewSwitcher"
                , new { mobile = true, returnUrl = Request.Url.PathAndQuery }
                , new { rel = "external" })
        }
    </div>
}

既然有這個View了,我們接下來要開始撰寫處理這個View的Controller,如下,當第一次進來的時候,變數mobile會是false,因為我們希望切換成Desktop,所以和IsMobileDevice判斷的時候,就會false,然後進入最下面的設定,也就是SetOverriddenBrowser()這個方法,這邊使用列舉型別BrowserOverride來設定並產生HttpBrowserCapabilitiesBass的實體,這裡是指定為選擇Desktop的HttpBrowserCapabilitiesBass實體,然後,就會重新倒回這個頁面一次。

( 其實這裡利用的概念,是使用HttpContext.Item來存放這些HttpBrowserCapabilitiesBass的實體,也就是HttpBrowserCapabilitiesWrapper,而在進去查看,是利用這個物件的屬性來判別是不是Mobile裝置,而這次MVC 4的方法,其實也都是在控制HttpContext.item,並非控制原本的HttpContext.Request,但詳細的細節,未來可能還要再去看原始碼 )

public class ViewSwitcherController : Controller
{
    public RedirectResult SwitchView(bool mobile, string returnUrl) {
        if (Request.Browser.IsMobileDevice == mobile)
            //這行會將HttpBrowserCapabilitiesBass的實體清掉。
            HttpContext.ClearOverriddenBrowser();
        else
            //這行會設定HttpBrowserCapabilitiesBass的實體。
            HttpContext.SetOverriddenBrowser(mobile ? BrowserOverride.Mobile : BrowserOverride.Desktop);

        return Redirect(returnUrl);
    }
}

所以當繞回View的時候,碰到這段判斷邏輯,就會判斷為false,( 因為現在是Desktop ),也因此,下面的連結就會顯示是否切換成Mobile。

@if (ViewContext.HttpContext.GetOverriddenBrowser().IsMobileDevice)

如果此時又按下切換成Mobile的連結,回到Controller時後,遇到此判斷,因傳入的mobile變數為true,且我們原本的裝置就是Mobile,所以下面這段程式碼就會成立。

( Request.Browser是不變的,也就是目前瀏覽器的狀態 )

if (Request.Browser.IsMobileDevice == mobile)

於是會執行這行,而這行就會把HttpBrowserCapabilitiesBass的實體清除。

HttpContext.ClearOverriddenBrowser();

雖然清除了,但是回到View時,View的建構子又會將Request.Browser ( HttpBrowserCapabilitiesWarpper )放一份到HttpContext.Item裡面,因此我們的裝置原本為Mobile,所以,遇到View的判斷,又會顯示Desktop的連結。

基本上這樣就形成了互相切換的機制,而關鍵點就在於這切換機制使用一個叫做Browser Overriding的機制,他可以去設定不同的請求來源( 例如是Mobile或是Desktop ),因還沒看到原始碼,目前我看起來此機制是會去判斷HttpContext.Item裡面的HttpBrowserCapabilitiesWarpper,而MVC 4提供了以下一些方法可以去控制。

HttpContext.SetOverriddenBrowser(userAgentString)
設定模擬瀏覽器的類型,會寫入一個HttpBrowserCapabilities的實體。
HttpContext.GetOverriddenUserAgent()
取得模擬瀏覽器類型的字串。
HttpContext.GetOverriddenBrowser()
取得HttpBrowserCapabilitiesBase的實體。
HttpContext.ClearOverriddenBrowser()
清除所有HttpBrowserCapabilitiesBase 的實體。

最後,我們把寫好的_ViewSwitcher放到要切換的頁面上,如下,我們使用Html.Partial這個HTML Helper方法,來載入剛剛寫好的_ViewSwitcher。

<div data-role="page" data-theme="a">
    @Html.Partial("_ViewSwitcher")

    <div data-role="header">
        <h1>@ViewBag.Title</h1>
    </div>

    <div data-role="content">
        @RenderSection("featured", false)
        @RenderBody()        
    </div>

</div>

這樣就完成了!!

最後,默認的情況下,這些覆蓋的資訊,會存一份於Cookie,所以如果畫面留在Desktop的Mobile裝置,這些模擬資訊會持續保留;此外如果想要替換存取位置,可以替換默認的提供者 ( BrowserOverrideStores.Current )。

總結,這次的文章內容,超級難打,如有錯誤的話,也煩請糾正指教,非常感謝。

參考資料

2 則留言:

  1. 想請教一下, 個人在測試這個功能時, 會發生用手機測試完之後, 再用PC測試, 再改手機就固定在PC的畫面勒, 15分鐘就又回復原狀, 不知版大是否有發生過?

    回覆刪除
  2. 小弟我沒有實測過耶....歹勢,幫不上忙>"<..

    回覆刪除