xaml - 当我更改主题设置时,为什么我的 AdaptiveTrigger 会触发?

标签 xaml windows-store-apps uwp windows-10 visualstatemanager

我有一个使用 AdaptiveTrigger 来适应不同设备外形的用户界面.特别是,我有一个 SplitView - 当最小窗口宽度分别为 1000 epx 和 600 epx 时,具有两个状态触发器的基于 shell 菜单。 600 epx 状态触发器可以在某些横向模式下的移动设备上触发,具体取决于它们的外形和比例因子,这是预期的行为。

但是,我注意到在桌面上,只要我更改主题设置(例如在暗模式和亮模式之间切换),600 epx 状态触发器就会在后台触发(将 ShellSplitView.DisplayModeOverlay 更改为 CompactOverlay ) ,更改强调色,或切换高对比度模式;在移动模拟器和设备上,当我转到“设置”应用程序、更改主题设置并返回我的应用程序时,它就会触发。最特别的是,这只发生在默认状态下,并且只有在我通过调整桌面上的窗口大小或旋转移动模拟器或设备来触发任何状态触发器之后。返回应用程序后再次调整大小/旋转会使问题消失。我以前在任何其他应用程序中都没有看到这一点,包括 Microsoft 的应用程序或任何第三方 UWP 应用程序。

我已经确认这不是由干扰状态触发器的其他代码引起的,方法是在一个空白 UWP 项目中成功重现该问题,该项目的单个页面只包含 SplitView具有任意数量的视觉状态(和一些文本内容):

<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState>
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="1000"/>
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="ShellSplitView.DisplayMode" Value="Inline"/>
                        <Setter Target="ShellSplitView.IsPaneOpen" Value="True"/>
                    </VisualState.Setters>
                </VisualState>
                <VisualState>
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="600"/>
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="ShellSplitView.DisplayMode" Value="CompactOverlay"/>
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <SplitView
            x:Name="ShellSplitView"
            CompactPaneLength="48"
            DisplayMode="Overlay"
            IsPaneOpen="False"
            OpenPaneLength="256">
            <SplitView.Content>
                <TextBlock Text="Content"/>
            </SplitView.Content>
            <SplitView.Pane>
                <TextBlock Text="Pane"/>
            </SplitView.Pane>
        </SplitView>
    </Grid>
</Page>

您可以尝试通过创建一个空白 UWP 项目、将 MainPage.xaml 的内容替换为上述 XAML 并运行该项目来自行重现该问题。

考虑到我所做的只是更改主题设置,我不明白为什么任何状态触发器都会触发。事实上,根据 this guide在 MSDN 上,默认值反射(reflect)在 SplitView元素的属性应该自动重新应用:

When you use state triggers, you don't need to define an empty DefaultState. The default settings are reapplied automatically when the conditions of the state trigger are no longer met.



根据 Windows.UI.Xaml.AdaptiveTrigger page本身:

By default, the StackPanel orientation is Vertical. When the window width is >= 720 effective pixels, the VisualState change is triggered, and the StackPanel orientation is changed to Horizontal.



......这共同强化了我的观点 - 当我更改主题设置时窗口宽度不会改变,所以我不明白为什么状态触发器会在不应该启动时启动,为什么只有在我已经通过调整窗口大小或旋转设备触发状态更改。

那么为什么会发生这种情况,我该如何解决呢?

最佳答案

此问题似乎已在所有设备系列的 Windows 10 周年更新中得到修复。状态触发器在不应该激活时将不再激活,并且现在可以正确重新应用在状态触发器之外指定的默认值。

  • 您不需要此解决方法 如果您的应用仅在 1607 分支(内部版本 14393 )或更新版本上运行。请注意,这是指项目属性中指定的最低版本,而不是目标版本。
  • 您需要此解决方法 如果您的应用程序将在 1511 分支(构建 10586 )或 1507 分支(构建 10240 )上运行,即使它在具有较新版本的设备上运行正常。


  • 不幸的是,如果不向 VisualStateGroup 添加默认状态,我就无法解决这个问题。无论如何,使用最小维度为 0 epx 的状态触发器(您不需要任何 setter - 您只需要一个状态触发器):
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState>
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="1000"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="ShellSplitView.DisplayMode" Value="Inline"/>
                    <Setter Target="ShellSplitView.IsPaneOpen" Value="True"/>
                </VisualState.Setters>
            </VisualState>
            <VisualState>
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="600"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="ShellSplitView.DisplayMode" Value="CompactOverlay"/>
                </VisualState.Setters>
            </VisualState>
            <VisualState>
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0"/>
                </VisualState.StateTriggers>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    

    至于为什么会发生这种情况,我的猜测是 VisualStateManager正在尝试在系统主题更新时进入一个状态,但由于没有为初始(或“默认”或“正常”)状态定义,它必须选择下一个最佳选择。我仍然不明白,为什么 VisualStateManager首先更新系统主题时必须更改视觉状态...不要ThemeResource自己刷新?为什么他们会依赖 VisualStateManager ?

    有趣的是,大多数关于 UWP 中自适应触发器的第三方教程已经这样做了。尚不清楚作者是否意识到了这个问题,或者他们是否只是因为他们在 Silverlight/WPF 时代习惯于这样做而添加了默认状态。但是,根据上面的文档和其他正确的 UWP 行为,这可能是一个极端情况。

    关于xaml - 当我更改主题设置时,为什么我的 AdaptiveTrigger 会触发?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37358867/

    相关文章:

    c# - 从 .net 4.5 中的 XAML 绑定(bind)到对象的属性

    c# - Windows 应用商店应用程序 - 旁加载和 Beta 测试

    c# - 有什么方法可以在UWP应用程序和WPF应用程序之间共享代码?

    c# - 将宽度/高度设置为在 xaml 中成比例?

    c# - ReSharper WPF错误: “Cannot resolve symbol ” MyVariable“due to unknown DataContext”

    c# - WPF MVVM ComboBox具有默认选定值

    windows - 我可以禁用Win10 S模式支持以通过Windows应用商店审查吗?

    c# - 如何创建集合 (1 :n) relation

    uwp - 如何在 UWP 中数据绑定(bind)到 RichEditBox 的纯文本值?

    javascript - 如何从 WinJS ListView 中删除悬停属性?