Опубликован: 05.08.2010 | Доступ: свободный | Студентов: 2006 / 44 | Оценка: 4.50 / 4.40 | Длительность: 60:26:00
Самостоятельная работа 8:

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

Программирование элемента

Если интерфейсную часть окна можно оформить через XAML, то логику программы возможно реализовать только в кодовой части. Сейчас мы немного покодируем на C# и добавим элементу некоторую функциональность.

  • В панели Solution Explorer откройте файл Window1.xaml.cs и дополните его следующим кодом
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.Navigation;
using System.Windows.Shapes;
    
namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        System.Windows.Media.Brush color;
        bool colorFlag = true;
    
        public Window1()
        {
            InitializeComponent();
    
            // Регистрируем обработчик события щелчка на кнопке Btn1
            Btn1.Click += new RoutedEventHandler(Btn1_Click);
            // Запоминаем начальный цвет фона окна
            color = this.Window.Background;
        }
    
        void Btn1_Click(object sender, RoutedEventArgs e)
        {
            // Меняем цвет фона кнопки 
            if (colorFlag)
                this.Window.Background = System.Windows.Media.Brushes.Purple;
            else
                this.Window.Background = color;
    
            colorFlag = !colorFlag;
        }
    }
}
  • Запустите приложение - теперь оно стало реагировать на щелчок курсора мыши и менять цвет клиентской области окна

Объект Application

Любое приложение использует класс Application, который организует его подключение к модели событий операционной системы с помощью метода Run(). Объект Application отвечает за управление временем жизни приложения, отслеживает видимые окна, освобождает ресурсы и контролирует глобальное состояние приложения. Метод Run() запускает диспетчер среды исполнения, который начинает посылать события и сообщения компонентам приложения.

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

Время жизни приложения WPF (и объекта Application ) состоит из следующих этапов:

  1. Конструируется объект Application
  2. Вызывается его метод Run()
  3. Возбуждается событие Application.Startup
  4. Пользовательский код конструирует один или несколько объектов Window (или Page ) и приложение выполняет работу
  5. Вызывается метод Application.Shutdown()
  6. Вызывается метод Application.Exit()

При создании заготовки нашего WPF-приложения мастер создал два файла с типовыми именами, связанные с объектом Application: App.xaml и App.xaml.cs. Если их открыть, то мы не увидим и намека на создание объекта Application, объекта Window и вызова метода Run(). Разработчики платформы WPF решили, что это стандартные операции для любого приложения и явно их прописывать в коде заготовки необязательно. Компилятор сам неявно создает объект Application при компиляции WPF-проекта, сам создает объект Window (или Page ) и передает его методу Application.Run().

Иными словами, за кулисами работы компилятора выполняется примерно такой код

/// <summary>
/// MyApp
/// </summary>
public partial class App : System.Windows.Application
{
    public App()
    {
        System.Windows.Window win = new System.Windows.Window();
        win.Title = "Hello World";
        win.Show();
    }
    
    /// <summary>
    /// Application entry point 
    /// </summary>
    [System.STAThreadAttribute()]
    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    public static void Main()
    {
        App app = new App();
        app.Run();
    }
}

Однако ссылка на стартовое окно приложения все же имеется в заготовке - это атрибут StartupUri="Window1.xaml" в файле App.xaml. Если этот атрибут убрать, то приложение не запустится как не имеющее точки входа. Чтобы лучше понять механизм неявного запуска WPF-приложения, давайте чуток поэкспериментируем с объектом Application.

  • Полностью уберите из дескриптора Application в файле App.xaml атрибут StartupUri="Window1.xaml" и запустите наш проект с мультимедийной кнопкой - стартовое окно приложения не запускается

Как и в любом другом приложении, если в процессе выполнения возникла исключительная ситуация и программист не предусмотрел ее обработку с помощью блоков try-catch-finally, то стандартное поведение объекта Application - выдать сообщение об ошибке и прервать работу приложения. Но возможны случаи, когда ошибка возникнет не на уровне приложения, а например, в самой платформе или среде выполнения. Для таких ситуаций предусмотрено событие Application.DispatcherUnhandledException, которое выдает диспетчер сообщений и которое мы можем обработать в своем приложении.

Попробуем, при выбранном атрибуте StartupUri="Window1.xaml" дескриптора объекта приложения в файле App.xaml, запустить наше стартовое окно другим способом.

  • Модифицируйте файл App.xaml.cs с расширением библиотечного класса Application следующим образом
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Windows;
    
namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public App()
        {
            // Подписались на событие, что запущен объект Application 
            this.Startup += new StartupEventHandler(App_Startup);
            // На всякий случай подписались на событие необработанных исключений
            this.DispatcherUnhandledException += App_DispatcherUnhandledException;
        }
    
        void App_DispatcherUnhandledException(object sender, 
            System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            e.Handled = true;// Продолжить выполнение
        }
    
        void App_Startup(object sender, StartupEventArgs e)
        {
            // Создаем объект стартового окна
            Window1 win = new Window1();
            // Настраиваем объект окна
            win.Title = "Перекрывающий заголовок окна";
            // Показываем окно
            win.Show();
        }
    }
}
  • Запустите приложение - оно заработало как и в стандартном случае

Для создания стартового окна мы использовали обработчик события Application.Startup, хотя можно было это сделать и в конструкторе App() класса приложения. Для данного простого упражнения это не важно, но лучше всегда использовать обработчик события Startup. Мы можем в конструкторе затребовать такие возможности объекта приложения, которые на этапе срабатывания конструктора еще не готовы, например, еще не будет инициализировано свойство Application.Current. Это аналогично тому, как в технологии Windows Forms лучше использовать обработчик события Load формы, чем ее конструктор.

  • Откройте файл Window1.xaml.cs кодовой части стартового окна приложения, уже частично модифицированный нами ранее

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

  • Закомментируйте метод InitializeComponent() и запустите проект - компилятор выдаст ошибку, что в коде делается попытка обратиться к несуществующим объектам, которые мы сами кодировали. Если бы мы не дополнили кодовую часть, то ошибки бы не было, но и окно формы появилось бы пустым
  • Не снимая комментарии с вызова метода InitializeComponent(), добавьте после него вызов статического метода Application.LoadComponent()
public Window1()
        {
            //InitializeComponent();
            Application.LoadComponent(this, new Uri("Window1.xaml", UriKind.Relative));
    
            // Регистрируем обработчик события щелчка на кнопке Btn1
            Btn1.Click += new RoutedEventHandler(Btn1_Click);
            // Запоминаем начальный цвет фона окна
            color = this.Window.Background;
        }
  • Запустите проект - приложение работает как ни в чем не бывало

В конструкторе объекта Uri мы сами указываем файл с дескрипторным интерфейсом окна, а вторым параметром говорим, что искать его нужно по относительному пути от корня местонахождения сборки. Но лучше пользоваться вызовом неявного метода InitializeComponent() приложения, так надежнее.

Этот простой пример не претендует на мировой шедевр, зато дает некоторое начальное представление о технологии WPF. Технология сильно напоминает проектирование Web-приложений для ASP.NET. Там тоже есть декларативная и кодовая части (Source и Design), и также можно конструировать пользовательский интерфейс через любую часть. Но кодировать события и тонкие настройки возможно только через кодовую часть.

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

При выполнении в лабораторной работе упражнения №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" или один из зависимых от них компонентов. Не удается найти указанный файл.

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