Splitview – Hamburger menu của Windows 10

Hamburger menu tuy không quá xa lạ nhưng đã trở thành đặc trưng của một ứng dụng Windows 10. Khi trước developer muốn đem kiểu menu này từ app Android sang phải tìm đến thư viện hỗ trợ như SlideView, hoặc tự code. Nay kiểu menu này đã được Microsoft chính thức thừa nhận với control SplitView

Tạo trang Shell

SplitView sẽ xuất hiện ở tất cả các trang của app (có thể giấu ở 1 số trang).

Tạo một Page mới Shell.xaml và khai báo SplitView như sau:

  1. <SplitView x:Name="AppMenu" Background="Black" OpenPaneLength="240" CompactPaneLength="52" Grid.Row="1"
  2. DisplayMode="CompactOverlay" IsPaneOpen="False" PaneBackground="Gray" Content="{Binding}">
  3. <SplitView.Pane>
  4. <StackPanel x:Name="SplitViewPanePanel">
  5.  
  6. <RadioButton x:Name="MenuBtn" Click="MenuBtn_Click" Tag="&#xE700;" Content="Menu" GroupName="Menu"
  7. Style="{StaticResource MenuRadioButtonStyle}" Width="240" Height="40" FontSize="20"/>
  8.  
  9. <RadioButton x:Name="HomeBtn" Click="HomeBtn_Click" Tag="&#xE80F;" Content="Home" GroupName="PageView"
  10. Style="{StaticResource MenuRadioButtonStyle}" Width="240" Height="40" FontSize="20"/>
  11. <RadioButton x:Name="CallBtn" Click="CallBtn_Click" Tag="&#xE13A;" Content="Call" GroupName="PageView"
  12. Style="{StaticResource MenuRadioButtonStyle}" Width="240" Height="40" FontSize="20"/>
  13. <RadioButton x:Name="ContactBtn" Click="ContactBtn_Click" Tag="&#xE13D;" Content="Contact" GroupName="PageView"
  14. Style="{StaticResource MenuRadioButtonStyle}" Width="240" Height="40" FontSize="20"/>
  15. </StackPanel>
  16. </SplitView.Pane>
  17. </SplitView>

Có một số lưu ý sau:

  • Background sẽ là màu nền của nội dung bên phải, PaneBackground là màu nền của menu bên trái.
  • DisplayMode: có 4 chế độ mô tả theo hình, cho bạn tùy chọn

    DisplayMode
    DisplayMode
  • CompactPaneLength: độ rộng của menu khi thu nhỏ (required khi chọn DisplayMode là Compact)
  • OpenPaneLength: độ rộng của menu khi đã mở hết.
  • Pane là một UIElement, nơi chứa các item trong menu, chứa control gì cũng được, ở đây mình dùng list các RadioButton
  • Content cũng là UIElement, là nội dung app, thường sẽ là 1 Frame. Được Binding vào DataContext của Shell để thay đổi Frame khi đổi lựa chọn trong menu (Trình bày kĩ ở phần sau).
  • RadioButton dùng trong menu này đã được custom lại template trong MenuRadioButton style, tại sao dùng RadioButton và cách làm có thể xem ở bài viết này, hoặc nếu quá rườm rà thì dùng Button bình thường cũng không sao 😀

Sửa App.xaml.cs

Sửa OnLaunched của app để thay đổi Content của cửa sổ hiện tại thành trang Shell

  1. private Shell shell;
  2. protected override void OnLaunched(LaunchActivatedEventArgs e)
  3. {
  4.  
  5. #if DEBUG
  6. if (System.Diagnostics.Debugger.IsAttached)
  7. {
  8. this.DebugSettings.EnableFrameRateCounter = true;
  9. }
  10. #endif
  11.  
  12. this.shell = Window.Current.Content as Shell;
  13. Frame rootFrame = null;
  14.  
  15. // Do not repeat app initialization when the Window already has content,
  16. // just ensure that the window is active
  17. if (this.shell == null)
  18. {
  19. // create new shell
  20. this.shell = new Shell();
  21. }
  22.  
  23. // Do not repeat app initialization when the Window already has content,
  24. // just ensure that the window is active
  25. if (rootFrame == null)
  26. {
  27. // Create a Frame to act as the navigation context and navigate to the first page
  28. rootFrame = new Frame();
  29.  
  30. rootFrame.NavigationFailed += OnNavigationFailed;
  31.  
  32. if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
  33. {
  34. //TODO: Load state from previously suspended application
  35. }
  36. }
  37.  
  38. shell.DataContext = rootFrame;
  39.  
  40. // Place the shell with frame as content in the current Window
  41. Window.Current.Content = shell;
  42.  
  43. if (rootFrame.Content == null)
  44. {
  45. // When the navigation stack isn't restored navigate to the first page,
  46. // configuring the new page by passing required information as a navigation
  47. // parameter
  48. rootFrame.Navigate(typeof(HomePage), e.Arguments);
  49. }
  50. // Ensure the current window is active
  51. Window.Current.Activate();
  52. }

 

Giải thích cụ thể:

  • Tạo một trang Shell mới
    1. this.shell = Window.Current.Content as Shell;
    2. Frame rootFrame = null;
    3.  
    4. // Do not repeat app initialization when the Window already has content,
    5. // just ensure that the window is active
    6. if (this.shell == null)
    7. {
    8. // create new shell
    9. this.shell = new Shell();
    10. }
  • Sau khi tạo rootFrame, gán rootFrame vào DataContext của shell (đã được Binding vào Content của SplitView), và gán Windows.Current.Content cho Shell
    rootFrame   
    if (rootFrame == null)
    {
    	// Create a Frame to act as the navigation context and navigate to the first page
    	rootFrame = new Frame();
     
    	rootFrame.NavigationFailed += OnNavigationFailed;
     
    	if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
    	{
    	    //TODO: Load state from previously suspended application
    	}
    }
     
    shell.DataContext = rootFrame;
     
    // Place the shell with frame as content in the current Window
    Window.Current.Content = shell;
  • Lúc này trên app đã xuất hiện Menu, nhưng nội dung trống trơn là do chưa chuyển tới trang mặc định nào khi khởi động. Ta dùng rootFrame để chuyển tới trang mặc định đầu tiên của ứng dụng (ở đây là trang HomePage)
    if (rootFrame.Content == null)
    {
    	// When the navigation stack isn't restored navigate to the first page,
    	// configuring the new page by passing required information as a navigation
    	// parameter
    	rootFrame.Navigate(typeof(HomePage), e.Arguments);
    }
    // Ensure the current window is active
    Window.Current.Activate();

Xử lý sự kiện chọn trên menu

private void MenuBtn_Click(object sender, RoutedEventArgs e)
{
    AppMenu.IsPaneOpen = !AppMenu.IsPaneOpen;
}
 
private void HomeBtn_Click(object sender, RoutedEventArgs e)
{
    var frame = this.DataContext as Frame;
    Page page = frame?.Content as Page;
    if (page?.GetType() != typeof(HomePage))
    {
        frame.Navigate(typeof(HomePage));
    }
}

 

Khi click vào icon Hamburger menu, sẽ thay đổi trạng thái của menu

Khi chọn các icon Home, Phone, … sẽ thay đổi Frame:

  • Lấy Frame từ DataContext (rootFrame).
  • Kiểm tra Content của Frame này có phải là trang HomePage không ?Nếu không thì Navigate đến HomePage.

Kết quả:

Home Page
Home Page
Contact Page
Contact Page
Compact menu
Compact menu

Code demo bạn có thể tải tại đây

Hỏi tôi vài câu được hok?

Website này sử dụng Akismet để hạn chế spam. Tìm hiểu bình luận của bạn được duyệt như thế nào.