2012年8月11日 星期六

自訂 SettingsPane

在撰寫 Windows Metro App 時需注意一點,
所有與分享、搜尋、設定的入口都要做在 Charms 上面,
簡單的範例 MSDN 上都有,以分享、搜尋來說客製化 Layout 的需求不高,
但設定頁的需求就高得不得了嘍,特別寫篇來記錄如何自訂 SettingsPane Layout

在市集中有許多 App 包括 Store 本身,在 SettingPane 的某些選項點選後,
所呈現的流程不是將 App Frame 導至詳細的設定頁,而是在 SettingPane 上做變化,
但單純的 SettingPane 只能塞入 SettingsCommand,說穿了就是只能顯示文字按鍵,
要像其他 App 一樣放入更多的元件例如 ToggleSwitch、Button 就要使用其他方法,
方法參考自:Adding app settings using XAML

該範例是 Windows 8 CP 時釋出的,所以在 RP、RTM 的版本上是編不起來的,
但只需要做一些些修改,這份文件簡單的說,並不是提供把元件塞到 SettingPane 的方法,
而是自行實作一個寬為 346 pix 的 UserControl 來扮演 SettingPane,
Xaml 方面並沒有版本的差異,直接整篇都可以使用,
大致上就是記得設值給 Width、Height,還有 Back 按鍵的行為定義,
在文件中讓該 UserControl 自己隱藏,並將 SettingPane 秀出來,可以說裝得非常像。

假設我自訂了一個包括帳號密碼輸入框、登入與申請會員按鍵等元件的設定頁 MemberSettingPage
在使用方面,我習慣在開啟登入頁時再取得螢幕的高度,可以減少處理 WindowSizeChanged 的流程,
另外也要注意 Windows.Current.Activated 事件的處理,這是主視窗獲得、失去焦點時的事件,
在失去焦點時將 Popup 關閉,感覺這種狀況會發生在 Popup 顯示中且Charms 被觸發時,
但將 Popup.IsLightDismissEnabled 設為 true 即可讓 Popup 在失去焦點時自行關閉,
所以 Windows.Current.Activated 事件處理的重要性目前我還感覺不到,應該可以省略。

Popup settingsMemberPopup = null;
private void OnSettingCommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
    String strMemberTitle = LocalizedStrings.GetString("STRING_ID_SETTING_MEMBER");
    SettingsCommand cmdMember = new SettingsCommand("member", strMemberTitle, (x) =>
    {
        Rect bounds = Window.Current.Bounds;
        settingsMemberPopup = new Popup();
        settingsMemberPopup.IsLightDismissEnabled = true;
        settingsMemberPopup.Width = 346;
        settingsMemberPopup.Height = bounds.Height;
        settingsMemberPopup.Closed += OnPopupClosed;
        Window.Current.Activated += OnWindowActivated;

        MemberSettingPage mypane = new MemberSettingPage();
        mypane.Width = 346;
        mypane.Height = bounds.Height;

        settingsMemberPopup.Child = mypane;
        settingsMemberPopup.SetValue(Canvas.LeftProperty, bounds.Width - 346);
        settingsMemberPopup.SetValue(Canvas.TopProperty, 0);
        settingsMemberPopup.IsOpen = true;
    });
    args.Request.ApplicationCommands.Add(cmdMember);
}

private void OnWindowActivated(object sender, WindowActivatedEventArgs e)
{
    if (e.WindowActivationState == CoreWindowActivationState.Deactivated)
    {
        settingsMemberPopup.IsOpen = false;
    }
}

private void OnPopupClosed(object sender, object e)
{
    Window.Current.Activated -= OnWindowActivated;
}

沒有留言:

張貼留言