Взаимодействие окон
53WPF --- Элементы управления WPF --- Взаимодействие окон
Класс Application предоставляет два инструмента для получения доступа к другим окнам: свойство MainWindow и свойство Window. При желании отслеживать окна более специализированным образом — например, путем отслеживания экземпляров определенного класса Window, которые могут представлять документы — разработчик может добавлять в класс Application собственные статические свойства.
Разумеется, получение ссылки на другое окно — это только полдела. Также необходимо определиться со способом взаимодействия. В принципе необходимость во взаимодействии окон следует сводить к минимуму, поскольку это излишне усложняет код. Однако если действительно требуется, чтобы значение элемента управления в одном окне изменялось на основе действия, выполняемого пользователем в другом окне, тогда, конечно, лучше создать в целевом окне специальный метод. Это гарантирует правильную идентификацию зависимости и добавит еще один уровень косвенности, упрощающий подгонку изменений в интерфейсе окна.
Если два окна должны взаимодействовать между собой каким-то сложным образом, разрабатываются или развертываются отдельно либо подвержены изменениям, можно двинуться на шаг дальше и формализовать их взаимодействие, создав интерфейс с общедоступными методами и реализовав его в классе своего окна.
Ниже на рисунках представлены два примера реализации такой схемы. На первом рисунке показано окно, которое вынуждает второе окно обновлять свои данные в ответ на щелчок на кнопке. Это окно не пытается напрямую изменить пользовательский интерфейс второго окна; вместо этого оно полагается на специальный промежуточный метод по имени DoUpdate().
Второй пример иллюстрирует ситуацию, когда требуется обновление более одного окна. В этом случае действующее окно полагается на более высокоуровневый метод приложения, который вызывает методы, требуемые для обновления других окон (возможно, даже путем прохода по коллекции окон). Этот подход лучше, т.к. он работает на более высоком уровне. В подходе, показанном на первом рисунке, действующему окну не нужно знать ничего конкретного об элементах управления в получающем окне. В подходе, приведенном на втором рисунке, производится еще один шаг вперед: здесь действующему окну ничего не нужно знать даже о классе получающего окна:
При взаимодействии между окнами очень часто полезным оказывается метод Window.Activate(). Этот метод позволяет передавать команду активизации нужному окну. Можно также использовать свойство Window.IsActive для проверки того, является ли данное окно в текущий момент единственным активным окном.
В этом примере привязку можно ослабить. Вместо того, чтобы вызывать метод в разных окнах, класс Application может просто возбуждать событие и позволить окнам самостоятельно выбирать, как на него реагировать.
Поддержка команд WPF может помочь абстрагировать логику приложения. Команды представляют собой специфические для приложений задачи и могут инициироваться любым способом.
Примеры, приведенные на рисунках, показывают, как отдельные окна (обычно немодальные) могут инициировать друг в друге различные действия. Однако существуют и более простые модели взаимодействия окон (такие как модели диалоговых окон), а также модели, которые дополняют данную (вроде моделей владения окнами).
Владение окнами
В .NET окно может "владеть" другими окнами. Окна, имеющие окно-владельца, удобно применять для плавающих окон панелей инструментов и окон команд. Одним из примеров такого окна является окно Find and Replace (Найти и заменить) в Microsoft Word. Когда окно-владелец сворачивается, окно, которым оно владеет, тоже автоматически сворачивается. Когда имеющее владельца окно перекрывает окно, которое им владеет, оно всегда отображается сверху.
Для поддержки владения окна класс Window предлагает два свойства: Owner и OwnedWindows. Свойство Owner представляет собой ссылку, которая указывает на окно, владеющее текущим окном (если таковое имеется), а свойство OwnedWindows — коллекцию всех окон, которыми владеет текущее окно (опять-таки, если они есть). Настройка владения окна подразумевает просто установку свойства Owner, как показано ниже:
//Создание нового окна.
ToolWindow winTool = new ToolWindow();
// Назначение текущего окна владельцем.
winTool.Owner = this;
// Отображение окна, принадлежащего окну-владельцу.
winTool.Show ();
Окна, обладающие окном-владельцем, всегда отображаются как немодальные. Чтобы удалить такое окно, нужно всего лишь установить для его свойства Owner значение null.
WPF не включает системы для построения многодокументных приложений (Multiple Document Interface — MDI). Если необходимо более сложное управление окнами, придется разработать его самостоятельно (или приобрести нужный компонент у независимых разработчиков).
Окно, имеющее владельца, может само владеть каким-нибудь другим окном, которое, в свою очередь, может владеть еще каким-нибудь окном и т.д. (хотя практическая пригодность такого проектного решения весьма сомнительна). Единственным ограничением является то, что окно не может владеть самим собой, а также то, что два окна не могут владеть друг другом.