Search code examples
uwpwinrt-xamltemplate10hamburger-menu

Start UWP App with Hamburger Menu collapsed - Template10


I am new to UWP and am using Template 10. I have done a lot of WPF though. I would like the app to start with the hamburger menu open or closed based on how the user left it when they last used the app. To that end, I have made a preference and I bound IsOpen to a property in my settings view model.

However, it does not work. When starting the application, the property in the view model is always set to true from the control. I added a button to change the view model property (which would do a raisepropertychanged) and it did not toggle the menu. However, toggling the menu the from the UI with the mouse will call the setter in my view model.

Here is what I did:

  1. I created a new project using the Hamburger template.

  2. I added a new property to SettingsService. It mirrors the format of the other properties in Settings Service

    public bool HamburgerIsOpen
    {
        get { return _helper.Read<bool>(nameof(HamburgerIsOpen), true); }
        set
        {
            _helper.Write(nameof(HamburgerIsOpen), value);
        }
    }
    
  3. I added a new property to SettingsPartViewModel. It mirrors the format of the other properties in SettingsPartViewModel

    public bool HamburgerIsOpen
    {
        get { return _settings.HamburgerIsOpen; }
        set { _settings.HamburgerIsOpen = value; base.RaisePropertyChanged(); }
    }
    
  4. I updated Shell.xaml adding a datacontext and the binding

<Page.DataContext>
     <viewModels:SettingsPageViewModel x:Name="ViewModel" />
</Page.DataContext>

<Controls:HamburgerMenu x:Name="MyHamburgerMenu" IsOpen="{x:Bind ViewModel.SettingsPartViewModel.HamburgerIsOpen, Mode=TwoWay}">

The control is definitely setting IsOpen to true on start even though it did a get first that returned false.

Any ideas how I can do this?

Thanks.


Solution

  • OK - here is what I ended up doing. It seems simpler to me than keeping track of loading, etc. This still feels like a bug to me in the Template 10, but this will work around it. Long story short, I don't do the binding in XAML, I do it after the page is loaded

    Shell.xaml -> create an event handler for Loaded on the page, no binding on IsOpen and set the data context.

    Loaded="Shell_OnLoaded"
    ...
    <Page.DataContext>
        <viewModels:SettingsPageViewModel x:Name="ViewModel" />
    </Page.DataContext>
    
    <Controls:HamburgerMenu x:Name="MyHamburgerMenu">
    

    Shell.xaml.cs -> here is the event handler for IsLoaded. It sets the binding AFTER the page is loaded. This stops the Hamburger control from setting the setting to true on load.

            private void Shell_OnLoaded(object sender, RoutedEventArgs e)
            {
               // now that the hamburger control is loaded, bind it for the future opening and closing
               // if you bind it in XAML, the control always passes the value of true on load to the binding
               // so the control always starts open
               Binding myBinding = new Binding
               {
                   Path = new PropertyPath("HamburgerIsOpen"),
                   Source = Services.SettingsServices.SettingsService.Instance,
                   Mode = BindingMode.TwoWay
               };
               MyHamburgerMenu.SetBinding(HamburgerMenu.IsOpenProperty, myBinding);
            }
    

    SettingsPageViewModel.cs -> define the property

            public bool HamburgerIsOpen
            {
                get { return _settings.HamburgerIsOpen; }
                set { _settings.HamburgerIsOpen = value; base.RaisePropertyChanged(); }
            }
    

    SettingsService.cs -> define the save mechanism. No need to call the view like other properties in SettingsService do...

            public bool HamburgerIsOpen
            {
                get { return _helper.Read<bool>(nameof(HamburgerIsOpen), true); }
                set
                {
                    _helper.Write(nameof(HamburgerIsOpen), value);
                }
            }