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:

[codesyntax lang=”xml” lines=”fancy” title=”Shell.xaml”]

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

[/codesyntax]

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

[codesyntax lang=”csharp” lines=”fancy” title=”App.xaml.cs – OnLaunched”]

private Shell shell;
protected override void OnLaunched(LaunchActivatedEventArgs e)
{

#if DEBUG
    if (System.Diagnostics.Debugger.IsAttached)
    {
        this.DebugSettings.EnableFrameRateCounter = true;
    }
#endif

    this.shell = Window.Current.Content as Shell;
    Frame rootFrame = null;

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (this.shell == null)
    {
        // create new shell
        this.shell = new Shell();
    }

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    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;

    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();
}

[/codesyntax]

 

Giải thích cụ thể:

  • Tạo một trang Shell mới[codesyntax lang=”csharp” lines=”fancy” title=”Create new Shell”]
    this.shell = Window.Current.Content as Shell;
    Frame rootFrame = null;
    
    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active
    if (this.shell == null)
    {
        // create new shell
        this.shell = new Shell();
    }

    [/codesyntax]

  • 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[codesyntax lang=”csharp” title=”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;

    [/codesyntax]

  • 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)[codesyntax lang=”csharp” title=”Navigate to 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();

    [/codesyntax]

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

[codesyntax lang=”csharp” title=”Menu events”]

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));
    }
}

[/codesyntax]

 

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

Leave a Reply

Your email address will not be published. Required fields are marked *