Опубликован: 05.08.2010 | Уровень: специалист | Доступ: свободно
Самостоятельная работа 8:

Создание приложений WPF

Упражнение 2. Окна в WPF

В данном упражнении мы будем говорить об окнах WPF и одновременно иллюстрировать сказанное на ряде примеров. Окна создаются не как самоцель - это удобный способ инкапсуляции (сокрытия, упаковки) некоторой функциональности. Окно представляет собой самый верхний уровень взаимодействия с пользователем (завершенной целостности) и не может быть частью другого окна.

Окна бывают модальными и немодальными. Модальное окно блокирует все другие окна приложения до его закрытия, переключая на себя взаимодействие приложения с операционной системой (если не создано в отдельном потоке). Окна бывают SDI и MDI - с однодокументным и многодокументным пользовательским интерфейсом. В последнем случае MDI-окно создает каркас для своих дочерних окон. В современном программировании все чаще стали создавать только SDI-приложения.

Для удобства все примеры упражнения мы упакуем в отдельные окна, которые будем вызывать из главного окна приложения.

Создание стартового окна приложения

  • Добавьте к решению WpfApp новый проект с именем WpfApp2, согласно окну мастера, и назначьте его стартовым

  • В панели Solution Explorer переименуйте файл Window1.xaml в Window0.xaml (автоматически переименуется и файл Window1.xaml.cs )
  • Откройте файлы App.xaml, Window0.xaml, Window0.xaml.cs проекта WpfApp2 и замените все вхождения Window1 на Window0
  • В дескрипторной части файла Window0.xaml замените секцию <Grid> на менеджер размещения <StackPanel> и включите в него кнопку вызова окна первого примера
<Window x:Class="WpfApp2.Window0"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window0" 
    Height="300" Width="300"
    SizeToContent="WidthAndHeight"
    MinWidth="300"
    MaxWidth="400"
    MinHeight="100"
    WindowStartupLocation="CenterScreen"
        >
    <StackPanel>
        <Button Margin="5" Click="LifeEvents">1) События времени жизни окна</Button>
    </StackPanel>
</Window>

Свойство SizeToContent устанавливает начальный размер окна по размеру содержимого. Это не мешает пользователю в дальнейшем интерактивно менять размер окна. Однако установка свойств MinWidth, MaxWidth, MinHeight, MaxHeight устанавливают разрешенные диапазоны интерактивного изменения размеров окна. В таком режиме параметры установки жестких размеров Width и Height не работают. Возможность интерактивно менять размеры окна определяется свойством ResizeMode. Начальное положение окна определяется свойством WindowStartupLocation.

Элемент StackPanel обеспечит нам вертикальное размещение кнопок для запуска разных примеров упражнения и по умолчанию занимает всю клиентскую область главного окна Window0. Параметр Margin элемента Button задает отступы вокруг кнопки. Подписаться на события окна мы можем в декларативной или кодовой части проекта, но при этом обязательно должны быть созданы заготовки обработчиков. Мы подписываемся на событие Click кнопки декларативно. Поэтому параметр Click нужно набирать вручную, чтобы мастер создал соответствующий обработчик в кодовой части окна.

  • Откройте кодовую часть окна Window0 и заполните обработчик LifeEvents() вызовом еще несуществующего окна примера 1 (мы его создадим на следующем этапе)
private void LifeEvents(object sender, RoutedEventArgs e)
        {
            Window1 wnd1 = new Window1();
            wnd1.ShowInTaskbar = false; // Не показывать в панели задач
            wnd1.ShowDialog();          // Показать в модальном режиме
        }

Последовательность событий времени жизни окна WPF

Следует отметить, что любое окно WPF также, как и объект Application приложения, имеет этапы своей жизни:

  1. Вызывается конструктор - создается объект окна
  2. Возбуждается событие Window.Initialized - окно инициализировало декларативные элементы
  3. Возбуждается событие Window.Activated - окно получило фокус ввода
  4. Возбуждается событие Window.Deactivated - окно теряет фокус ввода
  5. Возбуждается событие Window.Loaded - окно построено, но еще не отображено
  6. Возбуждается событие Window.ContentRenderer - окно только-что отображено на экране
  7. Пользователь взаимодействует с окном - рабочий режим окна
  8. Возбуждается событие Window.Closing - поступила требование закрыть окно, которое еще можно отменить
  9. Возбуждается событие Window.Closed - окно разрушено и не подлежит восстановлению
  10. Возбуждается событие Window.Unloaded - окно выгружено из памяти

События Activated и Deactivated могут генерироваться много раз в процессе работы пользователя, если он переключается с одного окна на другое.

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

  • Вызовите контекстное меню для имени проекта WpfApp2 и добавьте новое окно с именем Window1 командой Window

  • Заполните декларативную часть окна Window1 следующим кодом (на события в дескрипторе Window подписывайтесь вручную, чтобы создать обработчики)
<Window x:Class="WpfApp2.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
        
    Initialized="Window_Initialized"
    Activated="Window_Activated"
    Deactivated="Window_Deactivated"
    Loaded="Window_Loaded"
    ContentRendered="Window_ContentRendered"
    Closing="Window_Closing"
    Unloaded="Window_Unloaded"
    Closed="Window_Closed"
        >
    <Grid>
        <Button Click="Button_Click">Закрыть окно</Button>
    </Grid>
</Window>
  • Кодовую часть окна Window1 заполните следующим кодом
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
    
namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            System.Diagnostics.Debug.WriteLine("Сработал конструктор окна");
    
            InitializeComponent();
        }
    
        private void Window_Initialized(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Возбудилось событие Initialized окна");
        }
    
        private void Window_Activated(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Возбудилось событие Activated окна");
        }
    
        private void Window_Deactivated(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Возбудилось событие Deactivated окна");
        }
    
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Возбудилось событие Loaded окна");
        }
    
        private void Window_ContentRendered(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Возбудилось событие ContentRendered окна");
        }
    
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Возбудилось событие Closing окна");
            if (MessageBox.Show("Вы уверены, что хотите закрыть окно?",
                "Подтверждение", MessageBoxButton.YesNo) == MessageBoxResult.No)
                e.Cancel = true; // Не закрывать
        }
    
        private void Window_Unloaded(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Возбудилось событие Unloaded окна");
        }
    
        private void Window_Closed(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Возбудилось событие Closed окна");
        }
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
    }
}
  • Запустите приложение, вызовите окно Window1 и закройте его
  • Откройте панель Output оболочки, переключите ее в режим "Show output from: Debug" и просмотрите последовательность срабатывания упомянутых выше обработчиков
Сработал конструктор окна
Возбудилось событие Initialized окна
Возбудилось событие Activated окна
Возбудилось событие Loaded окна
Возбудилось событие ContentRendered окна
Возбудилось событие Closing окна
Возбудилось событие Deactivated окна
Возбудилось событие Activated окна
Возбудилось событие Deactivated окна
Возбудилось событие Closed окна
Возбудилось событие Unloaded окна

Открытие окна в немодальном режиме может выполняться любым из двух равноценных способов:

  1. wnd1.Show();
  2. wnd1.Visibility = Visibility.Visible;

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

Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Microsoft.Xna.Framework.Graphics;

   

namespace Application1

{

    public partial class MainForm : Form

    {

        // Объявим поле графического устройства для видимости в методах

        GraphicsDevice device;

   

        public MainForm()

        {

            InitializeComponent();

   

            // Подпишемся на событие Load формы

            this.Load += new EventHandler(MainForm_Load);

   

            // Попишемся на событие FormClosed формы

            this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed);

        }

   

        void MainForm_FormClosed(object sender, FormClosedEventArgs e)

        {

            //  Удаляем (освобождаем) устройство

            device.Dispose();

            // На всякий случай присваиваем ссылке на устройство значение null

            device = null;       

        }

   

        void MainForm_Load(object sender, EventArgs e)

        {

            // Создаем объект представления для настройки графического устройства

            PresentationParameters presentParams = new PresentationParameters();

            // Настраиваем объект представления через его свойства

            presentParams.IsFullScreen = false; // Включаем оконный режим

            presentParams.BackBufferCount = 1;  // Включаем задний буфер

                                                // для двойной буферизации

            // Переключение переднего и заднего буферов

            // должно осуществляться с максимальной эффективностью

            presentParams.SwapEffect = SwapEffect.Discard;

            // Устанавливаем размеры заднего буфера по клиентской области окна формы

            presentParams.BackBufferWidth = this.ClientSize.Width;

            presentParams.BackBufferHeight = this.ClientSize.Height;

   

            // Создадим графическое устройство с заданными настройками

            device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,

                this.Handle, presentParams);

        }

   

        protected override void OnPaint(PaintEventArgs e)

        {

            device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);

   

            base.OnPaint(e);

        }

    }

}

Выбрасывается исключение:

Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл.

Делаю все пунктуально. В чем может быть проблема?

Юрий Макушин
Юрий Макушин
Россия, Москва, РЭА им. Плеханова, 2004