Почему мой AdaptiveTrigger срабатывает, когда я меняю настройки темы?

У меня есть пользовательский интерфейс, который адаптируется к различным форм-факторам устройства с помощью AdaptiveTrigger. В частности, у меня есть меню оболочки на основе SplitView с двумя триггерами состояния, когда минимальная ширина окна составляет 1000 epx и 600 epx соответственно. Триггер состояния 600 epx может срабатывать на определенных мобильных устройствах в ландшафтном режиме в зависимости от их форм-фактора и коэффициента масштабирования, и это предполагаемое поведение.

Однако я заметил, что на рабочем столе триггер состояния 600 epx срабатывает в фоновом режиме (изменение ShellSplitView.DisplayMode с Overlay на 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 и запустив проект.

Учитывая все, что я сделал, это изменил настройки темы, я не понимаю, почему срабатывает какой-либо из триггеров состояния. Фактически, согласно этому руководству в MSDN , значения по умолчанию, отраженные в атрибутах элемента SplitView, должны быть повторно применены автоматически:

Когда вы используете триггеры состояния, вам не нужно определять пустой DefaultState. Настройки по умолчанию применяются автоматически, когда условия триггера состояния больше не выполняются.

И согласно самой Windows.UI.Xaml.AdaptiveTrigger page :

По умолчанию ориентация StackPanel равна Vertical. Когда ширина окна составляет> = 720 эффективных пикселей, запускается VisualState изменение, и StackPanel ориентация изменяется на Horizontal.

... которые вместе подтверждают мою точку зрения - ширина окна не меняется, когда я меняю настройки темы, поэтому я не понимаю, почему триггер состояния срабатывает, когда не должен, и почему только после того, как я вызвал изменение состояния, изменив размер окна или повернув устройство.

Так почему это происходит и как это исправить?


person BoltClock    schedule 21.05.2016    source источник


Ответы (1)


Эта проблема, по-видимому, была исправлена ​​в юбилейном обновлении Windows 10 для всех семейств устройств. Триггеры состояния больше не будут активироваться, если они не должны этого делать, а значения по умолчанию, указанные вне триггеров состояния, теперь правильно повторно применяются.

  • Этот обходной путь не требуется, если ваше приложение будет работать только в ветке 1607 (сборка 14393) или новее. Обратите внимание, что это относится к минимальной версии, указанной в свойствах вашего проекта, а не к целевой версии.

  • Этот обходной путь вам понадобится, если ваше приложение будет работать в ветке 1511 (сборка 10586) или 1507 (сборка 10240), даже если она будет корректно работать на устройствах с более новыми сборками.


К сожалению, мне не удалось обойти эту проблему без простого добавления состояния по умолчанию к VisualStateGroup в любом случае, используя триггер состояния с минимальным размером 0 epx (вам не нужны никакие сеттеры - вам просто нужен триггер состояния) :

<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 должен изменять визуальные состояния, когда системная тема обновляется в первую очередь ... не обновляются ли ThemeResources сами по себе? Зачем им зависеть от VisualStateManager?

Интересно отметить, что большинство сторонних руководств по адаптивным триггерам в UWP уже делают это. Неясно, знали ли авторы об этой проблеме или добавили ли они состояние по умолчанию просто потому, что они привыкли делать это во времена Silverlight / WPF. Однако, исходя из приведенной выше документации и правильного поведения UWP, это, вероятно, крайний случай.

person BoltClock    schedule 21.05.2016