Отображение нескольких представлений для приложения

Макет, показывающий приложение с несколькими окнами

Помогите пользователям работать эффективнее, дав им возможность открывать независимые части приложения в отдельных окнах. Если создать для приложения несколько окон, они будут отображаться отдельно на панели задач. Пользователи могут перемещать, отображать, скрывать окна приложения и менять их размеры независимо друг от друга, а также переключаться между окнами, как будто это разные приложения.

Важные API: пространство имен Windows.UI.ViewManagement, пространство имен Windows.UI.WindowManagement.

Когда приложение должно использовать несколько представлений?

Существует ряд сценариев, для которых может быть удобным использование нескольких представлений. Вот несколько примеров.

  • Приложение электронной почты, которое позволяет пользователям просматривать список полученных сообщений при составлении нового письма.
  • Приложение адресной книги, которое позволяет пользователям сравнить контактные данные для нескольких пользователей.
  • Приложение проигрывателя музыки, которое позволяет пользователям просматривать информацию о воспроизводимой музыке во время просмотра списка другой доступной музыки.
  • Приложение заметок, которое позволяет пользователям копировать сведения с одной страницы заметок на другую.
  • Приложение для чтения, которое дает пользователям возможность просматривать общий список заголовков и открывать несколько статей для чтения позже.

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

Чтобы создать отдельные экземпляры приложения (а не отдельные окна одного экземпляра), обратитесь к статье Создание приложения Windows с несколькими экземплярами.

Окна содержимого

Существует несколько способов размещения содержимого Windows внутри приложения.

  • CoreWindow/ApplicationView

    Представление приложения — это совокупность 1:1 потока и окна, которая используется приложением для отображения содержимого. Первое представление, создаваемое при запуске приложения, называется главным. Каждый объект CoreWindow и ApplicationView работает в своем собственном потоке. Работа с различными потоками пользовательского интерфейса может усложнить многооконные приложения.

    Основное представление приложения всегда размещается в ApplicationView. Содержимое в дополнительном окне может размещаться в ApplicationView или AppWindow.

    Узнайте, как использовать ApplicationView для отображения дополнительных окон в приложении, ознакомившись с разделом Использование ApplicationView.

  • AppWindow

    AppWindow упрощает создание многооконных приложений Windows, так как работает в том же потоке пользовательского интерфейса, из которого этот экземпляр создается.

    Класс AppWindow и другие интерфейсы API в пространстве имен WindowManagement доступны, начиная с Windows 10 версии 1903 (пакет SDK 18362). Если приложение нацелено на более ранние версии Windows 10, для создания дополнительных окон необходимо использовать ApplicationView.

    Узнайте, как использовать AppWindow для отображения дополнительных окон в приложении, ознакомившись с разделом Использование AppWindow.

    Примечание

    AppWindow сейчас находится на этапе предварительной версии. Это означает, что вы можете отправлять приложения, использующие AppWindow, в Store, но некоторые компоненты платформ не работают с AppWindow (см. раздел Ограничения).

  • DesktopWindowXamlSource (области XAML)

    Содержимое UWP XAML в приложении Win32 (использующем HWND), также известное как области XAML, размещается в DesktopWindowXamlSource.

    Чтобы узнать больше об областях XAML, ознакомьтесь с использованием API размещения UWP XAML в классическом приложении.

Создание кода, переносимого между окнами содержимого

Когда содержимое XAML отображается в CoreWindow, всегда существуют связанные с ним экземпляры ApplicationView и Window XAML. Интерфейсы API для этих классов можно использовать для получения таких сведений, как границы окна. Для получения экземпляра этих классов используется статический метод CoreWindow.GetForCurrentThread, метод ApplicationView.GetForCurrentView или свойство Window.Current. Кроме того, существует множество классов, использующих шаблон GetForCurrentView для получения экземпляра класса, например DisplayInformation.GetForCurrentView.

Эти API работают, так как для CoreWindow и ApplicationView существует только одно дерево содержимого XAML, поэтому XAML известен контекст размещения, то есть CoreWindow и ApplicationView.

Когда содержимое XAML выполняется в AppWindow или DesktopWindowXamlSource, можно одновременно выполнять несколько деревьев содержимого XAML в одном и том же потоке. В этом случае эти API не предоставляют нужных сведений, так как содержимое больше не выполняется в текущем экземпляре CoreWindow или ApplicationView (и экземпляре Window XAML).

Чтобы обеспечить правильную работу кода во всех окнах содержимого, необходимо заменить интерфейсы API, использующие CoreWindow, ApplicationView и Window, новыми API, которые получают контекст из класса XamlRoot. Класс XamlRoot представляет дерево содержимого XAML и сведения о контексте, в котором оно размещено, будь это CoreWindow, AppWindow или DesktopWindowXamlSource. Этот уровень абстракции позволяет писать единый код, не зависящий от того, в каком окне содержимого выполняется XAML.

В этой таблице показан код, который не работает правильно в окнах содержимого, и новый переносимый код, которым можно заменить предыдущий код, а также несколько API, которые не нужно изменять.

Если вы использовали… Замените на…
CoreWindow.GetForCurrentThread().Bounds uiElement.XamlRoot.Size
CoreWindow.GetForCurrentThread().SizeChanged uiElement.XamlRoot.Changed
CoreWindow.Visible uiElement.XamlRoot.IsHostVisible
CoreWindow.VisibilityChanged uiElement.XamlRoot.Changed
CoreWindow.GetForCurrentThread().GetKeyState Без изменений. Это поддерживается в AppWindow и DesktopWindowXamlSource.
CoreWindow.GetForCurrentThread().GetAsyncKeyState Без изменений. Это поддерживается в AppWindow и DesktopWindowXamlSource.
Window.Current Возвращает основной объект Window XAML, который жестко привязан к текущему экземпляру CoreWindow. См. примечание после таблицы.
Window.Current.Bounds uiElement.XamlRoot.Size
Window.Current.Content UIElement root = uiElement. XamlRoot. Содержимого
Window.Current.Compositor Без изменений. Это поддерживается в AppWindow и DesktopWindowXamlSource.
VisualTreeHelper.FindElementsInHostCoordinates
Хотя параметр UIElement является необязательным, метод вызывает исключение, если UIElement не предоставляется при размещении в области.
Определите элемент uiElement.XamlRoot как UIElement (не оставляйте его пустым).
VisualTreeHelper.GetOpenPopups
В приложениях с областями XAML это приведет к ошибке. В приложениях AppWindow это приведет к появлению всплывающих окон в главном окне.
VisualTreeHelper.GetOpenPopupsForXamlRoot(uiElement.XamlRoot)
FocusManager.GetFocusedElement FocusManager.GetFocusedElement(uiElement.XamlRoot)
contentDialog.ShowAsync() contentDialog.XamlRoot = uiElement.XamlRoot;
contentDialog.ShowAsync();
menuFlyout.ShowAt(null, new Point(10, 10)); menuFlyout.XamlRoot = uiElement.XamlRoot;
menuFlyout.ShowAt(null, new Point(10, 10));

Примечание

Для содержимого XAML в DesktopWindowXamlSource в потоке существует экземпляр CoreWindow или Window, но он всегда невидимый и имеет размер 1x1. Он по-прежнему доступен для приложения, но не возвращает действительные значения границы или видимости.

Для содержимого XAML в AppWindow всегда будет существовать только один экземпляр CoreWindow в одном потоке. При вызове API GetForCurrentView или GetForCurrentThread возвращается объект, отражающий состояние CoreWindow в потоке, а не экземпляров AppWindow, которые могут выполняться в том же потоке.

Что рекомендуется и что не рекомендуется делать

  • Укажите явную точку входа в дополнительное представление, используя глиф "Открыть новое окно".
  • Обсудите предназначение дополнительного представления для пользователей.
  • Убедитесь, что приложение является полностью функциональным в отдельном представлении и пользователи будут открывать дополнительное представление только для удобства.
  • Не используйте дополнительное представление для уведомлений и других временных визуальных элементов.