用 C# / XAML 製作 Windows 8 Apps 的 Header Menu
如果有看過官網的人
應該就會知道
Header Menu 目前官網只提供 JavaScript / HTML 的程式碼範例
這幾天剛好用到
於是就把實作的方法寫下來
Header Menu 一開始我以為用內建的控制項 ComboBox 就可以完成了
但拉出來的樣子,就差了很多
所以,只好自己做新的控制項
首先,新增一個「使用者控制項(User Control)」並取名為「HeaderMenuControl.xaml」
程式碼如下
將高度設為 180,寬度 設為 300
在內容的部分則插入一個「ListView」
並且新增幾個「ListViewItem」
做到這裡,其實就已經可以使用了
但按了之後,本身是沒有功能的,之後會再來說
回到原來主頁面
做一個「Header Title」
<Page | |
x:Class="HeaderMenu.MainPage" | |
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |
xmlns:local="using:HeaderMenu" | |
xmlns:common="using:HeaderMenu.Common" | |
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |
mc:Ignorable="d"> | |
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> | |
<Grid.RowDefinitions> | |
<RowDefinition Height="140"/> | |
<RowDefinition Height="*"/> | |
</Grid.RowDefinitions> | |
<Grid.ColumnDefinitions> | |
<ColumnDefinition Width="Auto"/> | |
<ColumnDefinition Width="*"/> | |
</Grid.ColumnDefinitions> | |
<Button x:Name="backButton" Grid.Column="0" Style="{StaticResource BackButtonStyle}"/> | |
<HyperlinkButton x:Name="pageTitle" Grid.Column="1" Content="Music ˅" FontSize="48" FontWeight="Normal" Margin="0,38,0,23" Click="pageTitle_Click_1" Foreground="#FF737375"/> | |
</Grid> | |
</Page> |
加入一個「Back」的「Button」
而這邊我們改使用 「HyperlinkButton」
讓滑鼠移過去或做點擊的時候有畫面上的回饋
並且我們在這個控制項上新增一個「Click」的事件
完成後
進到程式碼頁碼,也就是
MainPage.xaml
public sealed partial class MainPage : Page | |
{ | |
public Popup headerMenuPopup; | |
// 自訂的控制項 | |
public HeaderMenuControl headerMenuCtl; | |
// 是否已加入到 Popup 物件中 | |
public bool isAddedToPopup; | |
public MainPage() | |
{ | |
this.InitializeComponent(); | |
// 初始化自訂控制項,並給予寬度和高度的初始值(和在控制項的設定為一樣的值) | |
this.headerMenuCtl = new HeaderMenuControl() { Width = 250, Height = 210 }; | |
this.isAddedToPopup = false; | |
} | |
public static Popup ShowPopup(FrameworkElement source, UserControl control) | |
{ | |
// 宣告一個 Popup 物件 | |
Popup flyout = new Popup(); | |
var windowBounds = Window.Current.Bounds; | |
var rootVisual = Window.Current.Content; | |
GeneralTransform gt = source.TransformToVisual(rootVisual); | |
// 設定絕對位置的原點從 (0, 0) 開始算 | |
var absolutePosition = gt.TransformPoint(new Point(0, 0)); | |
control.Measure(new Size(Double.PositiveInfinity, double.PositiveInfinity)); | |
// 設定 Menu 要顯示的位置 | |
flyout.VerticalOffset = absolutePosition.Y + source.ActualHeight; | |
flyout.HorizontalOffset = absolutePosition.X; | |
flyout.IsLightDismissEnabled = true; | |
// 將我們自訂的控制項加到此 Popup 物件中 | |
flyout.Child = control; | |
// 設定 Menu 出現的動畫效果 | |
var transitions = new TransitionCollection(); | |
transitions.Add(new PopupThemeTransition() { FromHorizontalOffset = 0, FromVerticalOffset = -50 }); | |
flyout.ChildTransitions = transitions; | |
return flyout; | |
} | |
private void pageTitle_Click_1(object sender, RoutedEventArgs e) | |
{ | |
// 若是第一次按,則將物件新增到 Popup 物件裡。 | |
if (!this.isAddedToPopup) | |
{ | |
this.headerMenuPopup = ShowPopup(this.pageTitle, this.headerMenuCtl); | |
this.isAddedToPopup = true; | |
} | |
// 顯示 Popup | |
this.headerMenuPopup.IsOpen = true; | |
} | |
/// <summary> | |
/// 在此頁面即將離開時叫用。 | |
/// </summary> | |
/// <param name="e">描述在離開頁面後要執行的事件資料。 | |
/// Parameter 屬性通常用來設定頁面。</param> | |
protected override void OnNavigatedFrom(NavigationEventArgs e) | |
{ | |
} | |
} |
宣告一個我們剛才做的控制項物件到此類別中
我們在這個類別裡建立一個靜態函式 「ShowPopup」
事實上,他只會在第一次點到「Header」的時候執行
並將做好的一個 Popup 物件,回傳回來到我們在類別中宣告的一個 Popup 物件
執行後的結果如下:
然後你會發現一個問題
當我點選單中的選項時
選單並不會消失
為了解決這個問題
我們在呼叫 ShowPopup 之後
替 headerMenuCtl 建立一個「Tapped」的事件
當使用者點到控制項的任一位置時便會觸發此事件
private void pageTitle_Click_1(object sender, RoutedEventArgs e) | |
{ | |
// 若是第一次按,則將物件新增到 Popup 物件裡。 | |
if (!this.isAddedToPopup) | |
{ | |
this.headerMenuPopup = ShowPopup(this.pageTitle, this.headerMenuCtl); | |
this.headerMenuCtl.Tapped += headerMenuCtl_Tapped; | |
this.isAddedToPopup = true; | |
} | |
// 顯示 Popup | |
this.headerMenuPopup.IsOpen = true; | |
} | |
void headerMenuCtl_Tapped(object sender, TappedRoutedEventArgs e) | |
{ | |
this.headerMenuPopup.IsOpen = false; | |
} |