【问题标题】:Start UWP App with Hamburger Menu collapsed - Template10折叠汉堡菜单时启动 UWP 应用程序 - Template10
【发布时间】:2017-02-15 00:06:32
【问题描述】:

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

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

这是我所做的:

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

  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。

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

谢谢。

【问题讨论】:

    标签: uwp winrt-xaml template10 hamburger-menu


    【解决方案1】:

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

    1. 使用{x:Bind} 而不是{Binding},因为这样您就可以知道编译器是否可以找到您提供的绑定参考。
    2. viewModelShell.xaml 中创建a 属性(假设您使用的是Hamburger Template)或者如果不是?然后在使用HamburgerControlViewviewModel 中创建一个属性。
    3. 现在在property 中,您从Get 中的SettingsPageViewModel.SettingsPartViewModel.HamburgerIsOpen 获取数据,并将新值更新为set 中的相同值。这样您就可以在使用汉堡包的视图的viewModel 中获得所需的数据。
    4. 现在将x:Bind IsOpen 属性添加到Mode=TwoWay 中的属性。现在您将拥有一个功能齐全的汉堡菜单,其中包含恢复状态。 注意:如果您是 x:Binding 您的属性,请确保在绑定中添加 ViewModel. 前缀并将 &lt;DataContext&gt; 命名为 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 属性来处理汉堡菜单的打开/关闭

    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

    在您的汉堡控件中,将其链接到属性背后的代码,

    <Controls:HamburgerMenu x:Name="MyHamburgerMenu" IsOpen="{x:Bind IsHamOpen,Mode=TwoWay}">
    

    SettingsPageViewModel:

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

          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" />
    

    你有它。如果有任何问题,请告诉我。您可以在 cmets 部分与我联系

    【讨论】:

    【解决方案2】:

    好的——这就是我最终要做的。这对我来说似乎比跟踪加载等更简单。这对我来说仍然是模板 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);
                }
            }
    

    【讨论】:

      猜你喜欢
      • 2016-05-16
      • 1970-01-01
      • 1970-01-01
      • 2020-10-31
      • 2018-11-29
      • 1970-01-01
      • 1970-01-01
      • 2016-12-25
      • 1970-01-01
      相关资源
      最近更新 更多