使用折叠的汉堡包菜单启动 UWP 应用程序 - Template10

Start UWP App with Hamburger Menu collapsed - Template10

我是 UWP 的新手,正在使用模板 10。虽然我已经完成了很多 WPF。我希望该应用程序根据用户上次使用该应用程序时离开菜单的方式打开或关闭汉堡包菜单。为此,我做了一个偏好,并将 IsOpen 绑定到我的设置视图模型中的 属性 。

但是,它不起作用。启动应用程序时,视图模型中的 属性 始终从控件设置为 true。我添加了一个按钮来更改视图模型 属性(这将执行 raise属性changed)并且它没有切换菜单。但是,使用鼠标从 UI 切换菜单将在我的视图模型中调用 setter。

这是我所做的:

  1. 我使用汉堡模板创建了一个新项目。

  2. 我向 SettingsService 添加了一个新的 属性。它反映了设置服务中其他属性的格式

    public bool HamburgerIsOpen
    {
        get { return _helper.Read<bool>(nameof(HamburgerIsOpen), true); }
        set
        {
            _helper.Write(nameof(HamburgerIsOpen), value);
        }
    }
    
  3. 我向 SettingsPartViewModel 添加了一个新的 属性。它反映了 SettingsPartViewModel

    中其他属性的格式
    public bool HamburgerIsOpen
    {
        get { return _settings.HamburgerIsOpen; }
        set { _settings.HamburgerIsOpen = value; base.RaisePropertyChanged(); }
    }
    
  4. 我更新了 Shell.xaml 添加数据上下文和绑定

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

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

该控件肯定在启动时将 IsOpen 设置为 true,即使它首先执行返回 false 的操作。

有什么办法可以做到这一点吗?

谢谢。

您的汉堡包设置为打开的原因是因为它 IsOpen 属性 的后备值为 True。可能 {Binding} 失败了,因为它无法访问它或者它只是找不到它。因为您使用的是 UWPTemplate10。我会建议:

  1. 使用 {x:Bind} 而不是 {Binding} 因为这样您就可以知道编译器是否可以找到您提供的绑定引用。
  2. Shell.xamlviewModel 中创建一个 属性(假设您使用的是 Hamburger Template),或者如果不是?然后在使用 HamburgerControlViewviewModel 中创建一个 属性。
  3. 现在,在 property 中,您从 Get 中的 SettingsPageViewModel.SettingsPartViewModel.HamburgerIsOpen 获取数据,并将新值更新为 set 中的相同值。这样您就可以在使用汉堡包的视图的 viewModel 中获得所需的数据。
  4. 现在 x:Bind IsOpen 属性 到 属性 Mode=TwoWay。现在您将拥有一个功能齐全的带有恢复状态的汉堡包菜单。 注意: 如果您正在 x:Binding 您的 属性,请确保将 ViewModel. 前缀添加到您的绑定并将 <DataContext> 作为 ViewModel.

抱歉,我不得不删除所有代码,可能是因为我会把代码放在这里,而旧的代码不再相关或可以从编辑中找到。

说到重点,我已经解决了这个问题,似乎有一些调用服务调用 Hamburger 控件并将值设置为 false 当视图尚未加载时。我想出了一个相当厚颜无耻的方法来获得一个非常整洁的解决方案,有些人可能会说它不理想,但它是一个解决方案。

代码:

在您的 Shell.xmal 全局创建一个 bool 属性 例如:private bool loaded = false;。这是一个 属性 帮助我们知道视图是否已加载,因为对 setter 的所有调用都是在应用程序尚未加载时绕过它并允许getter 访问它。

现在在你的 Shell.xaml 构造函数中订阅 shell.Loaded 事件,

例如:this.Loaded += Shell_Loaded; //in the shell.xmal.cs constructor

Shell_Loaded 事件:

private void Shell_Loaded(object sender, RoutedEventArgs e)=>
        loaded = true;

注意方法语法是c#6.0中使用的语法,低版本请使用传统的{}.

还在 shell.xaml.cs 添加 bool 属性 来处理汉堡包菜单 open/closing

public bool IsHamOpen
    {
        get
        {
            return (new ViewModels.SettingsPageViewModel()).SettingsPartViewModel.IsHamOpen;
        }
        set
        {
            if (!value)
            {
                if (loaded)
                {
                    (new ViewModels.SettingsPageViewModel()).SettingsPartViewModel.IsHamOpen = value;
                }
                else
                    (new ViewModels.SettingsPageViewModel()).SettingsPartViewModel.IsHamOpen = true;
            }
            else
                (new ViewModels.SettingsPageViewModel()).SettingsPartViewModel.IsHamOpen = value;
        }
    }

请注意:我正在创建 ViewModel 的实例,以便通过 settingsViewModel 更改所有设置。如果某些设置开始变得有趣,我们就会知道在哪里可以找到它们。


你的Shell.xaml

在您的 Hamburger Control 中,link 将其添加到 属性、

后面的代码
<Controls:HamburgerMenu x:Name="MyHamburgerMenu" IsOpen="{x:Bind IsHamOpen,Mode=TwoWay}">

SettingsPageViewModel 中:

创建一个 属性 来处理对汉堡菜单所做的更改。通过这种方式,您还可以为用户提供一个简单的切换开关,以 select 默认打开或关闭他的汉堡包。

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

            //the below is to hide and show the hamburger button. 
            //If the it's open then hide button 
            //else show the button to open it.
            //this is just as per your requiremnts. 
            //I just wanted to put it in
            ShowHamburgerButton = !value;


        }
    }

在您的设置服务中:

添加一个属性读写设置并应用于汉堡包控件:

 public bool IsHamOpen
    {
        get { return _helper.Read<bool>(nameof(IsHamOpen), false); }
        set
        {
            _helper.Write(nameof(IsHamOpen), value);
            Views.Shell.HamburgerMenu.IsOpen = value;
        }
    }

最后 设置视图

这完全是可选的。如果你希望用户能够设置他对汉堡包控件的偏好,那么给 ViewModel 一个整洁的 toggleSwitchx:Bind 它。

<ToggleSwitch x:Name="OpenHamWhenStart"
                                  Header="Default Hamburger Open or Close"
                                  IsOn="{Binding IsHamOpen, Mode=TwoWay}"
                                  OffContent="Hamburger Menu is Closed"
                                  OnContent="Hamburger Menu is Open"
                                  RelativePanel.AlignLeftWithPanel="True"
                                  RelativePanel.Below="BusyTextTextBox" />

好了。如果有任何问题,请告诉我。你可以在评论区联系我

好的 - 这就是我最后做的。对我来说,这似乎比跟踪加载等更简单。这对我来说仍然是模板 10 中的一个错误,但这会解决它。长话短说,我不在 XAML 中进行绑定,我在页面加载后进行绑定

Shell.xaml -> 在页面上为 Loaded 创建事件处理程序,不绑定 IsOpen 并设置数据上下文。

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

<Controls:HamburgerMenu x:Name="MyHamburgerMenu">

Shell.xaml.cs -> 这是 IsLoaded 的事件处理程序。它设置绑定 AFTER 页面加载。这会阻止 Hamburger 控件在加载时将设置设置为 true。

        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 -> 定义 属性

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

SettingsService.cs -> 定义保存机制。无需像 SettingsService 中的其他属性那样调用视图...

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