Элемент ChildWindow

169

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

В Silverlight создать временное диалоговое окно легче всего с помощью элемента управления ChildWindow. Он имитирует модальное диалоговое окно. При выводе дочернего окна остальные окна отключаются и затеняются, в результате чего пользователь видит, что с ними сейчас нельзя работать. Затем дочернее окно выводится в центре экрана. Когда пользователь заканчивает работать с дочерним окном, ваш код закрывает его и делает активными остальные части приложения.

В примере, показанном на рисунке ниже, страница содержит кнопку. При щелчке на ней открывается дочернее окно, предлагающее ввести дополнительную информацию. При щелчке на кнопке закрытия (или на кнопке X, расположенной в верхнем правом углу) дочернее окно исчезает:

Вывод дочернего окна ChildWindow

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

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

Например, если в нижележащем интерфейсе выполняется анимация или видеофайл, они продолжают выполняться в качестве фона дочернего окна (если, конечно, не остановить их явно).

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

Элемент FloatableWindow можно применить для вывода одного или нескольких окон на фоне главной страницы Silverlight, причем, когда он активен, пользователь может взаимодействовать с нижележащим приложением. Обычно окно FloatableWindow используется для создания окон сообщений, плавающих панелей инструментов и областей, предназначенных для решения отдельных задач. Однако учитывайте, что плавающее окно может сбивать с толку пользователей.

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

Создание дочернего окна

Чтобы вывести элемент ChildWindow, его нужно создать на основе шаблона XAML так же, как любой другой пользовательский элемент управления. Для получения заготовки элемента ChildWindow в Visual Studio щелкните правой кнопкой мыши на имени проекта в окне Solution Explorer и выберите в контекстном меню команду Add --> New Item. Выделите шаблон Silverlight Child Window (Дочернее окно Silverlight), введите имя и щелкните на кнопке Add. Будут автоматически созданы шаблон XAML и файл с фоновым кодом. Кроме того, в проект будет добавлена ссылка на сборку System.Windows.Controls.dll, в которой определен элемент ChildWindow.

Класс ChildWindow наследует класс ContentControl, добавляя в него два дополнительных свойства (Title и DialogResult), два метода (Show() и Close()) и два события (Closing и Closed).

После добавления дочернего окна нужно заполнить его. Рабочая среда Visual Studio автоматически создает в шаблоне дочернего окна решетку Grid с двумя строками, размещает в нижней строке кнопки ОК и Cancel и создает обработчики событий, закрывающие окно. Вы можете удалить или отредактировать любые элементы, созданные программой Visual Studio.

Ниже приведена разметка дочернего окна, показанного на рисунке выше. Оно отображает две стандартные кнопки (OK и Отмена) и два текстовых поля для ввода информации пользователем:

<controls:ChildWindow x:Class="SilverlightTest.UserInformation"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
           Title="Ввод информации">
    <Grid x:Name="LayoutRoot" Margin="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <TextBlock>Имя:</TextBlock>
        <TextBox x:Name="txtFirstName" Grid.Column="1" Margin="3" Width="150"></TextBox>
        <TextBlock Grid.Row="1">Фамилия:</TextBlock>
        <TextBox x:Name="txtLastName" Grid.Row="1" Grid.Column="1" Margin="3"></TextBox>

        <Button Grid.Row="2" Margin="3" Width="75" Height="23" HorizontalAlignment="Right"  
                Content="OK" Click="cmdOK_Click"></Button>
        <Button Grid.Row="2" Grid.Column="1" Margin="3" Width="75" Height="23" HorizontalAlignment="Left"
                Content="Отмена" Click="cmdCancel_Click"></Button>
    </Grid>
</controls:ChildWindow>

Обработчики событий двух кнопок устанавливают свойство Childwindow.DialogResult булева типа. При щелчке на кнопке ОК оно принимает значение true, а на кнопке Cancel — значение false. Кроме того, свойство DialogResult может иметь значение null, указывающее на то, что пользователь не щелкнул ни на одной кнопке:

private void cmdOK_Click(object sender, RoutedEventArgs e)
{
        this.DialogResult = true;
}

private void cmdCancel_Click(object sender, RoutedEventArgs e)
{
        this.DialogResult = false;
}

При установке свойства DialogResult окно автоматически закрывается, возвращая управление корневому визуальному элементу. В некоторых ситуациях свойство DialogResult неуместно (например, при выводе окна "О программе", содержащего только кнопку Отмена). В этих случаях можно закрыть окно с помощью метода ChildWindow.Close(), а не путем установки свойства DialogResult.

Отображение дочернего окна

Для вывода дочернего окна на экран нужно создать экземпляр пользовательского класса Childwindow и вызвать метод Show():

UserInformation childWindow = new UserInformation();
childWindow.Show();

Несмотря на то что дочернее окно блокирует главный пользовательский интерфейс, метод Show() не блокирует выполнение кода приложения. Если поместить код после вызова метода Show(), он будет выполнен немедленно.

Такое поведение может привести к проблемам, если нужно создать реакцию на закрытие дочернего окна пользователем. В примере, показанном на рисунке выше, приложение получает информацию, введенную пользователем в дочернем окне и применяет ее для обновления главной страницы. Для реализаций этой задачи код должен реагировать на событие ChildWindow.Closed. Класс ChildWindow предоставляет также событие Closing, которое генерируется перед закрытием окна. Обычно оно используется для отмены закрытия, например, если введенной информации недостаточно.

Следовательно, обработчик события Closed нужно подключить до вызова метода Show() и отображения дочернего окна:

UserInformation childWindow = new UserInformation();
childWindow.Closed += childWindow_Closed;
childWindow.Show();

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

Если изменить приложение (например, поменять местами имя и фамилию), код сработает неправильно. Намного лучше создать дополнительный слой на основе открытых свойств и методов дочернего окна. Главная страница приложения может обратиться к свойствам и методам для получения необходимой информации. Указанные свойства и методы принадлежат пользовательскому классу ChildWindow, поэтому при корректировке интерфейса дочернего окна они сами напомнят о себе.

Например, в текущем примере можно добавить свойство UserName в класс UserInformation для возвращения имени и фамилии в одной строке:

public string UserName
{
       get { return txtFirstName.Text + " " + txtLastName.Text; }
}

Теперь имя и фамилию можно получить в обработчике события Closed:

private void childWindow_Closed(object sender, EventArgs e)
{
            if (childWindow.DialogResult == true)
                txtInfo.Text = "Добро пожаловать в приложение, "
                    + childWindow.UserName + "!";
}

Данный пример можно немного улучшить. Сейчас дочернее окно создается при каждом щелчке на кнопке "Ввод информации". В результате текстовые поля, предназначенные для ввода имени и фамилии, всегда появляются пустыми, даже если пользователь вводил в них информацию при предыдущей активизации окна. Для устранения этого недостатка можно добавить процедуру установки свойства UserName. Но есть еще лучший способ: сохранить объект UserInformation в памяти. В следующем коде объект Childwindow создается один раз как переменная главной страницы:

private UserInformation childWindow = new UserInformation();

public MainPage()
{
            InitializeComponent();
            childWindow.Closed += childWindow_Closed;
}

Как видите обработчик подключается к событию в конструкторе. Теперь объект UeerInformation будет сам сохранять свое состояние. В результате при каждом открытии дочернего окна введенная до этого информация появится в текстовых полях.

Окна ChildWindow рекомендуется использовать для вывода сообщений об ошибках. С их помощью вы сможете предоставить пользователю более мощные и эстетически привлекательные окна сообщений, чем стандартные окна MessageBox.

Создайте проект в Visual Studio на основе шаблона Silverlight Navigation Application, и вы увидите, что в шаблон уже встроены окна сообщений на основе Childwindow. В коде шаблона они называются ErrorWindow. Когда система генерирует исключения Application.UnhandledException, приложение выводит окна ErrorWindow, сообщающие о типах проблем и способах их устранения.

Пройди тесты
Лучший чат для C# программистов