Все необходимые для выполнения данной работы программы можно найти в прилагаемом каталоге.
Совершенно новой технологией программирования, которая стала поддерживаться Microsoft, начиная с библиотеки .NET Framework 3.0, является WPF - Windows Presentation Fondation (ранее носившая кодовое название Avalon). Эта библиотека еще не так развита в плане разнообразия библиотечных компонентов, как Windows Forms, но открывает для будущего широкие перспективы и является одной из частей нового API будущих версий Windows.
Существует два вида программ: для взаимодействия с людьми и для взаимодействия с другими программами. Технология WPF ориентирована как раз для взаимодействия с людьми. Многие подходы к созданию приложений в WPF ориентированы на упрощение процесса программирования пользовательских интерфейсов, что может значительно расширить круг программистов разного уровня подготовки, способных создавать приложения промышленного уровня.
Не смотря на то, что .NET создавалась независимой от платформы и должна бы работать на любой системе, WPF скорей всего, не сможет жить в любой среде - уж слишком сильно прослеживается связь с Windows и DirectX. Уже сейчас есть ограничения на используемую версию ОС Windows: минимальным требованием является Windows XP SP2. В Windows XP и Windows 2003 требуется отдельная установка, в то время как в Windows Vista данная подсистема уже предоставлена.
Новая графическая система Windows Presentation Foundation предназначена для создания пользовательских интерфейсов, 2D и 3D графики и т. д. Мощь WPF заключается в том, что 2D графика строится в векторном виде, а это значит, что интерфейсы будут максимально независимы от разрешения экрана и размера окна. Они будут легко масштабироваться без потери качества и быстро работать благодаря максимальному использованию возможностей современных графических ускорителей.
WPF включает в себя язык разметки XAML - Extensible Application Markup Language (произносится "заммль" - расширяемый язык разметки приложений ) как подмножество (диалект) языка XML и используется для создания и инициализации объектов. Использование языка XAML позволяет участвовать в разработке приложений людям с различными знаниями и опытом программирования. XAML - это мост между программистами и дизайнерами.
XAML использует основные четыре категории элементов:
WPF объединяет документы, формы и мультимедийное содержание в пакет, состоящий из языка разметки и процедурного языка программирования. Такой подход все больше стирает грань между Windows- и Web-программированием, сохраняя их лучшие достижения и традиции. Модель программирования WPF включает в себя одновременно декларативную (разметка) и императивную (кодовую, процедурную, бизнес-логику) части.
Теперь внешний вид приложения может создавать дизайнер, а не программист. Он может создавать окна в специализированных и простых программах, а программист в это время может писать логику. Таким образом, работа идет параллельно, а результирующий продукт может появиться на рынке быстрее. Когда дизайном занимается профессионал, то интерфейс будет смотреться намного лучше, чем работа программиста. Программисты должны писать код, а не рисовать.
Для дизайнеров Microsoft предлагает продукт под названием Microsoft Expression Blend (http://www.microsoft.com/expression). Это программа специально написана для специалистов интерфейса, а не программистов и не требует знания языков программирования.
WPF построен поверх DirectX, что позволяет использовать всю мощь современного "железа". Так, например, когда WPF определяет наличие видеокарты, поддерживающей аппаратное ускорение, он автоматически использует эти возможности карты. Использование WPF требует серьезной аппаратной поддержки - наличия графического процессора, поддерживающего DirectX 9.
Рендеринг в WPF – векторный, это дает возможность использовать преимущества мониторов с высоким разрешением, без каких либо дополнительных усилий программиста или пользователя. Интерфейс пользователя больше не зависит от конкретных разрешений, введено понятие "виртуального пиксела". WPF Framework позволяет программистам создавать продвинутые приложения с богатым пользовательским интерфейсом, работающие с мультимедиа, изощренно работать с документами: все это объединено в единой программной модели. WPF предлагает множество различных элементов управления для:
XAML содержит ровно одну корневую вершину и является деревом отображения. На вершине иерархии находится один из контейнерных объектов. Внутри этих объектов располагаются элементы управления и другие контейнеры. В XAML названия элементов всегда чувствительны к регистру и точно совпадают с именами классов, доступных в кодовой части WPF.
В этом упражнении мы просто продемонстрируем на простом примере некоторые мультимедийные возможности WPF.
Создайте проект WpfApp1 в решении WpfApp как показано на рисунке. Обратите внимание на необходимость
выбора библиотеки .NET Framework 3.0.
Оболочка создаст заготовку с рабочей областью, представленной на рисунке

Оболочка предоставляет возможность графического и дескрипторного
способов разработки пользовательского интерфейса, которые являются равнозначными.
Она сама подключила необходимые сборки и сгенерировала код поддержки WPF. На
данном этапе нас интересуют файлы: дескрипторный Window1.xaml и кодовый Window1.xaml.cs,
которые дополняют друг друга при описании одного и того же содержимого - класса Window1
(по умолчанию) в пространстве имен WpfApp1, совпадающем с названием проекта.
Платформа WPF проектировалась разработчиками с желанием отделить дизайнерскую часть пользовательского интерфейса от кодовой части программирования функциональности. Дизайнерская часть проектируется декларативно, чаще всего - с помощью графического дизайнера формы, который в автоматическом режиме генерирует соответствующий синтаксически правильный дескрипторный код на языке XAML.
Предполагается, что разработчик, занимающийся дизайном формы, не должен вмешиваться в часть XAML, а должен использовать только режим Design, чтобы не нарушить синтаксис XAML. Но на практике опытный разработчик создает интерфейс окна именно в дескрипторной части вручную, периодически проверяя представление через дизайнер окна.
В заготовки дескрипторного XAML-кода видно, что корнем приложения
будет контейнер <Window>, в который при развитии проекта будут включены дочерние
элементы. Все элементы WPF существуют в двух вариантах: дескрипторном
и объектном. Объектное описание размещается в пространствах имен, подключаемых
в кодовую часть проекта с помощью инструкции using для видимости компилятором.
Дескрипторное описание находится в двух пространствах имен: обычном и расширенном.
Эти пространства имен подключаются как значения атрибутов xmlns и xmlns:x в
корневом дескрипторе проекта
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Это не ссылки на какие-то страницы Интернета, таких страниц не существует, это разработчики платформы просто выбрали такие пространства имен. Если убрать эти атрибуты из корневого элемента дескрипторной части XAML проекта, то ни один дескриптор не будет виден оболочкой.
Нарушим правило невмешательства в XAML для неопытных пользователей и в демонстрационных целях с помощью только дескрипторного кода создадим простое изображение мультимедийной кнопки. Каждый дескриптор имеет свой тип и атрибуты, уточняющие его настройку. Как и в языке XML, в XAML используется вложенность дескрипторов. Язык XAML чувствителен к регистру символов, поэтому нужно следовать указаниям подсказчика IntalliSense.
Заполните вкладку XAML
следующим кодом<!-- Настройки всего окна -->
<Window x:Class="WpfApp1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="300"
Title="Упражнение 1"
x:Name="Window"
Background="Aqua">
<!-- Секция Resources для хранения ресурсов окна приложения -->
<Window.Resources>
<!-- Создаем шаблон с названием ClassButton для элементов типа Button -->
<ControlTemplate x:Key="ClassButton" TargetType="{x:Type Button}">
<!-- Секция для хранения ресурсов окна кнопки -->
<ControlTemplate.Resources>
<!-- Секция Storyboard для зажжения кнопки -->
<Storyboard x:Key="Timeline1">
<!-- За установленное время 0.3 секунды кнопка становится непрозрачной -->
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="glow"
Storyboard.TargetProperty="(UIElement.Opacity)">
<!-- Конечная точка анимации -->
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<!-- Секция Storyboard для затухания кнопки -->
<Storyboard x:Key="Timeline2">
<!-- За установленное время 0.3 секунды кнопка становится прозрачной -->
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="glow"
Storyboard.TargetProperty="(UIElement.Opacity)">
<!-- Конечная точка анимации -->
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<!-- Секция для описания кнопки -->
<!-- Наружная граница белая -->
<Border BorderBrush="#FFFFFFFF" BorderThickness="1,1,1,1"
CornerRadius="4,4,4,4">
<!-- Внутренняя граница черная -->
<Border x:Name="border" Background="#7F000000" BorderBrush="#FF000000"
BorderThickness="1,1,1,1" CornerRadius="4,4,4,4">
<Grid>
<Grid.RowDefinitions>
<!-- Верхняя половинка кнопки -->
<RowDefinition Height="0.5*" />
<!-- Нижняя половинка кнопки -->
<RowDefinition Height="0.5*" />
</Grid.RowDefinitions>
<!-- Рисуем подсветку кнопки -->
<Border Opacity="0" HorizontalAlignment="Stretch" x:Name="glow" Width="Auto"
Grid.RowSpan="2" CornerRadius="4,4,4,4">
<Border.Background>
<!-- Задаем радиальный градиент со смещением -->
<RadialGradientBrush>
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.702" ScaleY="2.243" />
<SkewTransform AngleX="0" AngleY="0" />
<RotateTransform Angle="0" />
<TranslateTransform X="-0.368" Y="-0.152" />
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<!-- Цвета градиента в формате ARGB -->
<GradientStop Color="#B28DBDFF" Offset="0" />
<GradientStop Color="#008DBDFF" Offset="1" />
</RadialGradientBrush>
</Border.Background>
</Border>
<!-- Рисуем блик -->
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
Width="Auto" Grid.RowSpan="2" />
<Border HorizontalAlignment="Stretch" x:Name="shine"
Width="Auto" CornerRadius="4,4,0,0">
<Border.Background>
<LinearGradientBrush StartPoint="0.494,0.028" EndPoint="0.494,0.889">
<GradientStop Color="#99FFFFFF" Offset="0" />
<GradientStop Color="#33FFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
</Border>
</Border>
<!-- Задаем тригеры, описывающие реакцию на события мыши -->
<ControlTemplate.Triggers>
<!-- Кнопка мыши нажата -->
<Trigger Property="IsPressed" Value="True">
<Setter Property="Opacity" TargetName="shine" Value="0.4" />
<Setter Property="Background" TargetName="border" Value="#CC000000" />
<Setter Property="Visibility" TargetName="glow" Value="Hidden" />
</Trigger>
<!-- Курсор над объектом -->
<Trigger Property="IsMouseOver" Value="True">
<!-- Заходит на объект - вызываем анимацию Timeline1 -->
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Timeline1}" />
</Trigger.EnterActions>
<!-- Уходит с объекта - вызываем анимацию Timeline2 -->
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource Timeline2}" />
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Grid>
<!-- Создаем экземпляр кнопки посредине окна -->
<Button x:Name="Btn1" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="176" Height="34"
Content="Мультимедийная кнопка" Foreground="#FFFFFFFF"
Template="{DynamicResource ClassButton}" />
</Grid>
</Window>
Запустите приложение
- должно получиться следующее
Выполните команду View/Other Windows/Document Outline
(либо щелкните на пиктограмме слева внизу в строке навигатора рабочей области),
чтобы открыть панель Document Outline (если она еще автоматически не
открылась)
Мы видим дерево всех дескрипторных элементов, составляющих проект. В Visual
Studio 2003 эта панель разрешала редактировать элементы, сейчас же она служит
только для просмотра дерева дескрипторных элементов или для быстрой навигации
по документу XAML. Обратите внимание, что корнем дерева объектов проекта является единственный класс,
в нашем случае, - класс Window. Возможны другие варианты корневого объекта,
например, Page. Но корень обязательно должен быть, причем, единственный. Он
и определяет тип приложения - Web или Windows.
Посмотрите XAML-дескриптор внутри контейнера <Grid>, там размещен экземпляр
кнопки Button, порожденный шаблоном ClassButton. Он и отображается на форме
проекта. Контейнер <Grid> XAML подобен контейнеру содержимого <body> в
HTML, которое отображается в окне (броузера или клиентского приложения). Все
компоненты панели Toolbox, которые мы будем перетаскивать на форму WPF в режиме
визуальной разработки интерфейса, будут представлены дескрипторами, размещенными
в контейнере <Grid>.
Если интерфейсную часть окна можно оформить через 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, который организует его подключение
к модели событий операционной системы с помощью метода Run(). Объект Application
отвечает за управление временем жизни приложения, отслеживает видимые окна,
освобождает ресурсы и контролирует глобальное состояние приложения. Метод Run()
запускает диспетчер среды исполнения, который начинает посылать события и сообщения
компонентам приложения.
В каждый момент времени может быть активен только один
объект Application и он будет работать до тех пор, пока приложение не завершится.
К исполняемому объекту Application можно получить доступ из любого места
приложения через статическое свойство Application.Current. Одна из основных
задач объекта Application состоит в том, чтобы контролировать время жизни процесса.
Конструирование объекта Application знаменует начало жизни приложения, а возврат
из его метода Run() - завершение приложения.
Время жизни приложения WPF (и объекта Application ) состоит из следующих этапов:
ApplicationRun()Application.StartupWindow (или Page ) и приложение выполняет работуApplication.Shutdown()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), и также можно конструировать пользовательский интерфейс через любую часть. Но кодировать события и тонкие настройки возможно только через кодовую часть.
В данном упражнении мы будем говорить об окнах WPF и одновременно иллюстрировать сказанное на ряде примеров. Окна создаются не как самоцель - это удобный способ инкапсуляции (сокрытия, упаковки) некоторой функциональности. Окно представляет собой самый верхний уровень взаимодействия с пользователем (завершенной целостности) и не может быть частью другого окна.
Окна бывают модальными
и немодальными. Модальное окно блокирует все другие окна приложения до его
закрытия, переключая на себя взаимодействие приложения с операционной системой
(если не создано в отдельном потоке). Окна бывают
Для удобства все примеры упражнения мы упакуем в отдельные окна, которые будем вызывать из главного окна приложения.
Добавьте к решению 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 также, как и объект Application приложения,
имеет этапы своей жизни:
Window.Initialized - окно инициализировало декларативные
элементыWindow.Activated - окно получило фокус вводаWindow.Deactivated - окно теряет фокус вводаWindow.Loaded - окно построено, но еще не отображеноWindow.ContentRenderer - окно только-что отображено
на экранеWindow.Closing - поступила требование закрыть окно,
которое еще можно отменитьWindow.Closed - окно разрушено и не подлежит восстановлению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 окна
Открытие окна в немодальном режиме может выполняться любым из двух равноценных способов:
wnd1.Show();wnd1.Visibility = Visibility.Visible;Если окну назначить владельца через свойство Owner, то при его открытии
в немодальном режиме оно будет размещаться всегда поверх владельца, а также
сворачиваться и закрываться вместе с ним. Такое окно не мешает владельцу получать
фокус ввода. Обычно владельца назначают окнам поиска и замены, инструментальным
окнам.
Одно и то же приложение может создавать несколько окон, которые одновременно могут быть открыты. Если этим окнам не назначен владелец, то при закрытии порождающего окна они так и останутся открытыми. Это можно проверить и на последнем примере, если выполнить следующее
LifeEvents() файла Window0.axml.cs код модального открытия окна wnd1.ShowModal() ;
на wnd1.Show() ;Window0 открыть несколько экземпляров окна Window1, затем закрыть
окно Window0После таких действий все дочерние окна остаюся открытыми и их нужно закрывать вручную (если только мы их запускали не из под оболочки). К тому же пиктограммы окон не отображаются в панели задач и стоит нам перекрыть экран другим окном, то эти окна придется закрывать либо, предварительно свернув все другие окна, либо через диспетчер задач.

Такое поведение не совсем хорошее, поэтому разработчики платформы WPF предусмотрели
в объекте Application соответствующие средства. Мы их рассмотрим в данном
упражнении.
Добавьте к решению
новый WPF-проект с именем WpfApp3 и назначьте
его стартовым
В панели Solution
Explorer удалите из проекта WpfApp3 файл с автоматически
созданным именем Window1.xaml и добавьте новый файл с именем WindowList.xaml (чтобы не переименовывать во многих местах)
Откройте файл App.xaml проекта WpfApp3 и
поменяйте значение параметра StartupUri объекта Application на имя файла нового стартового окна<Application x:Class="WpfApp3.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="WindowList.xaml"
>
</Application>
Откройте файл WindowList.xaml в режиме View
XAML и настройте стартовое окно следующим образом<Window x:Class="WpfApp3.WindowList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowList"
SizeToContent="WidthAndHeight"
MinWidth="200"
>
<StackPanel>
<Button Click="NewWindowClicked">Создать новое окно</Button>
<Button Click="ListOpenWindows">Список открытых окон</Button>
</StackPanel>
</Window>
Проследите, чтобы одновременно
были созданы зарегистрированные в кнопках обработчики
Модифицируйте файл WindowList.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.Shapes;
namespace WpfApp3
{
/// <summary>
/// Interaction logic for WindowList.xaml
/// </summary>
public partial class WindowList : Window
{
static int createCount;
public WindowList()
{
InitializeComponent();
// Определение заголовка окна
this.Title = "Окно № " + (createCount++).ToString();
}
private void NewWindowClicked(object sender, RoutedEventArgs e)
{
new WindowList().Show();
}
private void ListOpenWindows(object sender, RoutedEventArgs e)
{
StringBuilder sb = new StringBuilder();
foreach (Window openWindow in Application.Current.Windows)
sb.AppendLine(openWindow.Title);
MessageBox.Show(sb.ToString(), "Открытые окна приложения");
}
}
}
Запустите приложение
- оно хранит и выдает список открытых в текущий момент окон
Однако все окна, открытые приложением, приходится по-прежнему закрывать вручную. Для решения этой проблемы есть два пути:
Application.Current.MainWindow ссылку на это окноApplication.Current.Shutdown()Какой из этих двух вариантов будет работать, определяет свойство Application.Current.ShutdownMode.
Оно может принимать одно из следующих значений одноименного перечисления:
ShutdownMode.OnLastWindowClose - закрывать приложение вместе с закрытием
последнего окна (установлено по умолчанию)ShutdownMode.OnMainWindowClose - закрывать приложение вместе с закрытием
главного окнаShutdownMode.OnExplicitShutdown - закрывать приложение только тогда, когда
явно вызван метод Shutdown()Приложение в режиме ShutdownMode.OnExplicitShutdown может закрыться только
методом Shutdown(), но и в двух предыдущих режимах метод Shutdown() работает
всегда.
Испытаем оба способы.
Для разнообразия сделаем главным окно под номером 3, а во все окна добавим
кнопку вызова метода Shutdown().
Откройте файл WindowList.xaml в
режиме View XAML и добавьте к стартовому окну еще одну кнопку<Window x:Class="WpfApp3.WindowList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowList"
SizeToContent="WidthAndHeight"
MinWidth="200"
>
<StackPanel>
<Button Click="NewWindowClicked">Создать новое окно</Button>
<Button Click="ListOpenWindows">Список открытых окон</Button>
<Button Click="AllCloseWindows">Закрыть все окна</Button>
</StackPanel>
</Window>
Проследите, чтобы одновременно
был создан зарегистрированный в кнопке обработчик
Модифицируйте файл WindowList.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.Shapes;
namespace WpfApp3
{
/// <summary>
/// Interaction logic for WindowList.xaml
/// </summary>
public partial class WindowList : Window
{
static int createCount;
public WindowList()
{
InitializeComponent();
// Определение заголовка окна и назначение главного окна
if (createCount == 3)
{
Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
Application.Current.MainWindow = this;
this.Title = "Главное окно № " + (createCount++).ToString();
}
else
this.Title = "Окно № " + (createCount++).ToString();
}
private void NewWindowClicked(object sender, RoutedEventArgs e)
{
new WindowList().Show();
}
private void ListOpenWindows(object sender, RoutedEventArgs e)
{
StringBuilder sb = new StringBuilder();
foreach (Window openWindow in Application.Current.Windows)
sb.AppendLine(openWindow.Title);
MessageBox.Show(sb.ToString(), "Открытые окна приложения");
}
private void AllCloseWindows(object sender, RoutedEventArgs e)
{
//Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
Application.Current.Shutdown();// Закрывает при любом режиме
}
}
}
Запустите приложение
и убедитесь, что оно в любом месте закрывается методом Shutdown(),
а также при закрытии третьего окнаЕсли установить режим ShutdownMode.OnExplicitShutdown, то приложение
можно завершить только методом Shutdown().
Пользователи среды разработки (программисты) делятся на две категории: те,
кто разрабатывает законченные приложения и те, кто разрабатывает элементы управления,
в том числе - интерфейсные (визуальные). Последние конструируют из библиотечных
элементов укрупненные блоки, которые можно использовать при разработке интерфейса
окон: пользовательские (user control) и нестандартные (
Таким образом, пользовательские элементы управления (user control) - это
способ инкапсуляции (упаковки) частей графического интерфейса. Нестандартные
графические элементы (
В качестве базового для пользовательского элемента управления берется библиотечный
класс ContentControl или производный от него UserControl
из пространства имен System.Windows.Controls. В этом упражнении мы проиллюстрируем
создание и применение пользовательских элементов управления на примере инкапсуляции
кнопки Button.
Добавьте к решению
новый WPF-проект с именем WpfApp4 и назначьте его стартовым
В панели Solution Explorer
выделите узел проекта WpfApp4, в главном меню оболочки выполните
команду Add User Control и добавьте к проекту новый файл с именем MyUserControl.xaml
Модифицируйте интерфейсную
часть <UserControl x:Class="WpfApp4.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Button Click="Button_Click">Моя кнопка</Button>
</UserControl>
Модифицируйте кодовую
часть 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 WpfApp4
{
/// <summary>
/// Interaction logic for MyUserControl.xaml
/// </summary>
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Привет всем!", "Элемент UserControl");
}
}
}
Откомпилируйте (только
откомпилируйте!) проект WpfApp4, чтобы создать пользовательский элемент
для видимости его подсказчиком кода IntelliSense в файле окна
Откройте на редактирование
в режиме XAML файл Window1.xaml и измените его дескрипторный код так<Window x:Class="WpfApp4.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:My="clr-namespace:WpfApp4"
Title="Упражнение 4"
Width="200"
SizeToContent="Height"
WindowStartupLocation="CenterScreen"
>
<StackPanel>
<My:MyUserControl Margin="1"/>
<My:MyUserControl Margin="1"/>
</StackPanel>
</Window>
В дескриптор окна Window мы добавили пользовательское пространство имен WpfApp4 с
псевдонимом My, чтобы окно увидело пользовательский элемент. Мы жестко задали
ширину окна и сказали, чтобы по высоте окно подстраивалось под свое содержимое.
Мы установили начальное положение окна в центре экрана. В клиентскую область
окна мы поместили контейнер с двумя экземплярами пользовательского элемента.
Запустите на выполнение
проект WpfApp4 и испытайте работу простого пользовательского элемента
в составе окна приложения
WPF поддерживает переходы в стиле веб-обозревателя, которые могут использоваться в приложениях двух типов: автономных приложениях и XBAP ( XAML browser applications - приложения обозревателя XAML)
Платформа WPF имеет средства создавать страницы, которые в некоторых
случаях могут быть более привычны пользователю, чем оконные приложения. В страничных
приложениях содержимое страниц встраивается в специальный навигационный каркас,
поддерживающий навигационные ссылки и журнал навигации. Корневым узлом
в них является не класс Window, а производный от него класс NavigationWindow,
который добавляет стандартный интерфейс навигации и всю необходимую инфраструктуру.
Класс NavigationWindow имеет доступ к тем же самым средствам уровня приложения,
что и Window.
Добавьте к решению
новый проект с именем WpfApp5 и назначьте его стартовым
Удалите автоматически
созданный мастером файл Window1.xaml и добавьте к проекту вместо него новый
файл с именем NavExample.xaml по тому же оконному шаблону
Откройте файл App.xaml и скорректируйте атрибут StartupUri="NavExample.xaml"
Выполните проект WpfApp5,
чтобы убедиться в отсутствии ошибок
Откройте файл NavExample.xaml и скорректируйте его дескрипторный код так<NavigationWindow x:Class="WpfApp5.NavExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Упражнение 5"
Height="300"
Width="300"
WindowStartupLocation="CenterScreen"
>
</NavigationWindow>
Откройте
файл NavExample.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.Shapes;
using System.Windows.Navigation;
namespace WpfApp5
{
/// <summary>
/// Interaction logic for NavExample.xaml
/// </summary>
public partial class NavExample : NavigationWindow
{
public NavExample()
{
InitializeComponent();
//this.Navigate(new Page1());
}
}
}
Запустите проект -
пока мы видим пустой контейнер с заготовкой навигационного узла
Содержимое навигационного узла должно быть представлено классом, производным
от библиотечного класса Page. Создадим три пробные страницы содержимого
и подключим их к навигационному узлу с помощью метода Navigate().
Добавьте к проекту
новый элемент Page с именем Page1.xaml
Отредактируйте дискрипторную
часть файла Page1.xaml следующим образом<Page x:Class="WpfApp5.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel>
<TextBlock TextAlignment="Center" FontSize="24">Страница 1</TextBlock>
<TextBlock></TextBlock>
<TextBlock>
<Hyperlink Click="LinkClicked">На страницу 2</Hyperlink>
</TextBlock>
</StackPanel>
</Page>
Отредактируйте кодовую
часть - файл Page1.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 WpfApp5
{
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
}
private void LinkClicked(object sender, RoutedEventArgs e)
{
this.NavigationService.Navigate(new Page2());
}
}
}
Добавьте к проекту
новый элемент Page с именем Page2.axml
Отредактируйте
дискрипторную часть файла Page2.axml следующим образом<Page x:Class="WpfApp5.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page2"
>
<StackPanel>
<TextBlock TextAlignment="Center" FontSize="24">Страница 2</TextBlock>
</StackPanel>
</Page>
Добавьте в файл NavExample.xaml
атрибут Source, подключающий при запуске каркаса начальную страницу содержимого Page1.xaml (вместо этого можно было бы добавить в конструктор класса NavExample
кодовой части каркаса закомментированную строку создания экземпляра типа this.Navigate(new
Page1()); )<NavigationWindow x:Class="WpfApp5.NavExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Упражнение 5"
Height="300"
Width="300"
WindowStartupLocation="CenterScreen"
Source="Page1.xaml"
>
</NavigationWindow>
Запустите проект на
выполнение и пощелкайте на ссылках - пока все работаетМы создали каркас и две пустые страницы, которые ничего не делают. Каждая
страница является автономной, даже если наполнить ее элементами управления.
При переходе между страницами нужно научиться передавать информацию от странице
к странице, т.е. хранить их состояние. Должен быть общий почтовый ящик, не
зависящий от существования страниц, в котором бы эта информация хранилась.
В WPF для передачи данных между страницами можно использовать словарь (массив
пар "ключ-значение") Application.Current.Properties или
'зашивать' информацию прямо в объект новой страницы.
Продолжим развитие упражнение. Дополним первую страницу текстовым полем, через которое пользователь введет свое имя, а на второй странице выведем приветствие с этим именем через текстовую метку.
Добавьте к странице Page1 именованное текстовое поле с меткой следующим образом<Page x:Class="WpfApp5.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1"
>
<StackPanel>
<TextBlock TextAlignment="Center" FontSize="24">Страница 1</TextBlock>
<TextBlock></TextBlock>
<Label>Введите свое имя: </Label>
<TextBox Name="nameBox" Width="200"></TextBox>
<TextBlock></TextBlock>
<TextBlock>
<Hyperlink Click="LinkClicked">На страницу 2</Hyperlink>
</TextBlock>
</StackPanel>
</Page>
Объекту TextBox мы присвоили имя, чтобы можно было обращаться к нему из кода.
Измените кодовую часть
страницы Page1 следующим образом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 WpfApp5
{
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
}
private void LinkClicked(object sender, RoutedEventArgs e)
{
Page2 page2 = new Page2();
page2.Message = nameBox.Text + " !!!";// Зашиваем информацию в объект страницы
this.NavigationService.Navigate(page2);
}
}
}
Добавьте на страницу Page2 именованную текстовую метку и гиперссылку для перехода на Page3, а
также подпишитесь на событие Loaded страницы и на событие Click гиперссылки<Page x:Class="WpfApp5.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page2"
Loaded="Page_Loaded"
>
<StackPanel>
<TextBlock TextAlignment="Center" FontSize="24">Страница 2</TextBlock>
<TextBlock></TextBlock>
<TextBlock>Приветствуем Вас дорогой </TextBlock>
<Label Name="nameLabel"></Label>
<TextBlock Margin="0,10"> <!--Отступ сверху-->
<Hyperlink Click="LinkClicked">На страницу 3</Hyperlink>
</TextBlock>
</StackPanel>
</Page>
Объекту Label мы присвоили имя, чтобы можно было обращаться к нему
из кода.
Добавьте в кодовую
часть страницы Page2 публичное свойство, код присвоения текстовой
метке переданного текста в обработчике события Loaded и код перехода на следующую
страницу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 WpfApp5
{
public partial class Page2 : Page
{
public Page2()
{
InitializeComponent();
}
string message;
public string Message
{
set { message = value; }
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
nameLabel.Content = message;
}
private void LinkClicked(object sender, RoutedEventArgs e)
{
Page3 page3 = new Page3();
this.NavigationService.Navigate(page3);
}
}
}
Запустите приложение
- информация передается, но только по щелчку на ссылкеПо щелчку на кнопке навигации свежая информация из текстового поля не передается, потому что берется из журнала истории.
Заполните разметку
страницы Page3 следующим кодом<Page x:Class="WpfApp5.Page3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page3">
<StackPanel>
<!--Заголовок контекста страницы-->
<TextBlock TextAlignment="Center" FontSize="24">Страница 3
<TextBlock.Margin>0,0,0,10</TextBlock.Margin>
</TextBlock>
<!--Первая кнопка-->
<Button Content="Push Me!" FontSize="22" Height="50" Click="Button_Click">
<Button.Effect>
<DropShadowEffect />
</Button.Effect>
</Button>
<!--Вторая кнопка-->
<Button FontSize="22" Height="50" Margin="0,10" Click="Button_Click">
Кликни меня
<Button.Effect>
<DropShadowEffect />
</Button.Effect>
<Button.Foreground>
<LinearGradientBrush StartPoint="1,0" EndPoint="0,0">
<GradientStop Color="Red" Offset="0" />
<GradientStop Color="Orange" Offset=".17" />
<GradientStop Color="Yellow" Offset=".33" />
<GradientStop Color="Green" Offset=".5" />
<GradientStop Color="CornflowerBlue" Offset=".67" />
<GradientStop Color="Blue" Offset=".84" />
<GradientStop Color="BlueViolet" Offset="1" />
</LinearGradientBrush>
</Button.Foreground>
<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Red" Offset="0" />
<GradientStop Color="Orange" Offset=".17" />
<GradientStop Color="Yellow" Offset=".33" />
<GradientStop Color="Green" Offset=".5" />
<GradientStop Color="CornflowerBlue" Offset=".67" />
<GradientStop Color="Blue" Offset=".84" />
<GradientStop Color="BlueViolet" Offset="1" />
</LinearGradientBrush>
</Button.Background>
</Button>
</StackPanel>
</Page>
Обработчик события Click в дескрипторах кнопок нужно прописывать вручную,
чтобы оболочка создала их заготовки в файле кодовом части.
Прежде, чем заполнить кодовую часть страницы Page3, мы добавим к проекту новую
форму, чтобы показать
совместную работу технологий WPF и Windows Forms. В обработчик кнопок поместим
код запуска формы.
Добавьте к проекту WpfApp5 новую форму Form1
Поместите на форму
из панели Toolbox элемент DataGridView, установите его свойство Dock=Fill
и добавьте через интеллектуальный дескриптор ( SmartTag ) пару столбцов
Общий обработчик кнопок
в кодовой части Page3 заполните такprivate void Button_Click(object sender, RoutedEventArgs e)
{
Form1 frm = new Form1();
frm.ShowInTaskbar = false;// Не показывать кнопку формы в панели задач
frm.Show();
}
Запустите проект и
полюбуйтесь на дизайн новой страницы, а также убедитесь, что по щелчку запускается
форма Form1 с интерфейсом другой технологии
Этот пример иллюстирирует возможность совместного использования интерфейса Windows Forms и интерфейса WPF, но только на уровне отдельных окон. Смешивать интерфейсные компоненты разных технологий в одном окне нельзя, они построены на разных принципах. Но на уровне бизнес-логики вся мощь библиотеки .NET Framework и языка C# остается в распоряжении программиста.
Если программист реализует пользовательский интерфейс по технологии WPF, то он должен помнить, что WPF поддерживается только начиная с Windows XP (SP2), а в Windows 95, Windows 98, Windows 2000 - не поддерживается.

Все необходимые для выполнения данной работы программы можно найти в прилагаемом каталоге.
Совершенно новой технологией программирования, которая стала поддерживаться Microsoft, начиная с библиотеки .NET Framework 3.0, является WPF - Windows Presentation Fondation (ранее носившая кодовое название Avalon). Эта библиотека еще не так развита в плане разнообразия библиотечных компонентов, как Windows Forms, но открывает для будущего широкие перспективы и является одной из частей нового API будущих версий Windows.
Существует два вида программ: для взаимодействия с людьми и для взаимодействия с другими программами. Технология WPF ориентирована как раз для взаимодействия с людьми. Многие подходы к созданию приложений в WPF ориентированы на упрощение процесса программирования пользовательских интерфейсов, что может значительно расширить круг программистов разного уровня подготовки, способных создавать приложения промышленного уровня.
Не смотря на то, что .NET создавалась независимой от платформы и должна бы работать на любой системе, WPF скорей всего, не сможет жить в любой среде - уж слишком сильно прослеживается связь с Windows и DirectX. Уже сейчас есть ограничения на используемую версию ОС Windows: минимальным требованием является Windows XP SP2. В Windows XP и Windows 2003 требуется отдельная установка, в то время как в Windows Vista данная подсистема уже предоставлена.
Новая графическая система Windows Presentation Foundation предназначена для создания пользовательских интерфейсов, 2D и 3D графики и т. д. Мощь WPF заключается в том, что 2D графика строится в векторном виде, а это значит, что интерфейсы будут максимально независимы от разрешения экрана и размера окна. Они будут легко масштабироваться без потери качества и быстро работать благодаря максимальному использованию возможностей современных графических ускорителей.
WPF включает в себя язык разметки XAML - Extensible Application Markup Language (произносится "заммль" - расширяемый язык разметки приложений ) как подмножество (диалект) языка XML и используется для создания и инициализации объектов. Использование языка XAML позволяет участвовать в разработке приложений людям с различными знаниями и опытом программирования. XAML - это мост между программистами и дизайнерами.
XAML использует основные четыре категории элементов:
WPF объединяет документы, формы и мультимедийное содержание в пакет, состоящий из языка разметки и процедурного языка программирования. Такой подход все больше стирает грань между Windows- и Web-программированием, сохраняя их лучшие достижения и традиции. Модель программирования WPF включает в себя одновременно декларативную (разметка) и императивную (кодовую, процедурную, бизнес-логику) части.
Теперь внешний вид приложения может создавать дизайнер, а не программист. Он может создавать окна в специализированных и простых программах, а программист в это время может писать логику. Таким образом, работа идет параллельно, а результирующий продукт может появиться на рынке быстрее. Когда дизайном занимается профессионал, то интерфейс будет смотреться намного лучше, чем работа программиста. Программисты должны писать код, а не рисовать.
Для дизайнеров Microsoft предлагает продукт под названием Microsoft Expression Blend (http://www.microsoft.com/expression). Это программа специально написана для специалистов интерфейса, а не программистов и не требует знания языков программирования.
WPF построен поверх DirectX, что позволяет использовать всю мощь современного "железа". Так, например, когда WPF определяет наличие видеокарты, поддерживающей аппаратное ускорение, он автоматически использует эти возможности карты. Использование WPF требует серьезной аппаратной поддержки - наличия графического процессора, поддерживающего DirectX 9.
Рендеринг в WPF – векторный, это дает возможность использовать преимущества мониторов с высоким разрешением, без каких либо дополнительных усилий программиста или пользователя. Интерфейс пользователя больше не зависит от конкретных разрешений, введено понятие "виртуального пиксела". WPF Framework позволяет программистам создавать продвинутые приложения с богатым пользовательским интерфейсом, работающие с мультимедиа, изощренно работать с документами: все это объединено в единой программной модели. WPF предлагает множество различных элементов управления для:
XAML содержит ровно одну корневую вершину и является деревом отображения. На вершине иерархии находится один из контейнерных объектов. Внутри этих объектов располагаются элементы управления и другие контейнеры. В XAML названия элементов всегда чувствительны к регистру и точно совпадают с именами классов, доступных в кодовой части WPF.
В этом упражнении мы просто продемонстрируем на простом примере некоторые мультимедийные возможности WPF.
Создайте проект WpfApp1 в решении WpfApp как показано на рисунке. Обратите внимание на необходимость
выбора библиотеки .NET Framework 3.0.
Оболочка создаст заготовку с рабочей областью, представленной на рисунке

Оболочка предоставляет возможность графического и дескрипторного
способов разработки пользовательского интерфейса, которые являются равнозначными.
Она сама подключила необходимые сборки и сгенерировала код поддержки WPF. На
данном этапе нас интересуют файлы: дескрипторный Window1.xaml и кодовый Window1.xaml.cs,
которые дополняют друг друга при описании одного и того же содержимого - класса Window1
(по умолчанию) в пространстве имен WpfApp1, совпадающем с названием проекта.
Платформа WPF проектировалась разработчиками с желанием отделить дизайнерскую часть пользовательского интерфейса от кодовой части программирования функциональности. Дизайнерская часть проектируется декларативно, чаще всего - с помощью графического дизайнера формы, который в автоматическом режиме генерирует соответствующий синтаксически правильный дескрипторный код на языке XAML.
Предполагается, что разработчик, занимающийся дизайном формы, не должен вмешиваться в часть XAML, а должен использовать только режим Design, чтобы не нарушить синтаксис XAML. Но на практике опытный разработчик создает интерфейс окна именно в дескрипторной части вручную, периодически проверяя представление через дизайнер окна.
В заготовки дескрипторного XAML-кода видно, что корнем приложения
будет контейнер <Window>, в который при развитии проекта будут включены дочерние
элементы. Все элементы WPF существуют в двух вариантах: дескрипторном
и объектном. Объектное описание размещается в пространствах имен, подключаемых
в кодовую часть проекта с помощью инструкции using для видимости компилятором.
Дескрипторное описание находится в двух пространствах имен: обычном и расширенном.
Эти пространства имен подключаются как значения атрибутов xmlns и xmlns:x в
корневом дескрипторе проекта
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Это не ссылки на какие-то страницы Интернета, таких страниц не существует, это разработчики платформы просто выбрали такие пространства имен. Если убрать эти атрибуты из корневого элемента дескрипторной части XAML проекта, то ни один дескриптор не будет виден оболочкой.
Нарушим правило невмешательства в XAML для неопытных пользователей и в демонстрационных целях с помощью только дескрипторного кода создадим простое изображение мультимедийной кнопки. Каждый дескриптор имеет свой тип и атрибуты, уточняющие его настройку. Как и в языке XML, в XAML используется вложенность дескрипторов. Язык XAML чувствителен к регистру символов, поэтому нужно следовать указаниям подсказчика IntalliSense.
Заполните вкладку XAML
следующим кодом<!-- Настройки всего окна -->
<Window x:Class="WpfApp1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="300"
Title="Упражнение 1"
x:Name="Window"
Background="Aqua">
<!-- Секция Resources для хранения ресурсов окна приложения -->
<Window.Resources>
<!-- Создаем шаблон с названием ClassButton для элементов типа Button -->
<ControlTemplate x:Key="ClassButton" TargetType="{x:Type Button}">
<!-- Секция для хранения ресурсов окна кнопки -->
<ControlTemplate.Resources>
<!-- Секция Storyboard для зажжения кнопки -->
<Storyboard x:Key="Timeline1">
<!-- За установленное время 0.3 секунды кнопка становится непрозрачной -->
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="glow"
Storyboard.TargetProperty="(UIElement.Opacity)">
<!-- Конечная точка анимации -->
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<!-- Секция Storyboard для затухания кнопки -->
<Storyboard x:Key="Timeline2">
<!-- За установленное время 0.3 секунды кнопка становится прозрачной -->
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="glow"
Storyboard.TargetProperty="(UIElement.Opacity)">
<!-- Конечная точка анимации -->
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<!-- Секция для описания кнопки -->
<!-- Наружная граница белая -->
<Border BorderBrush="#FFFFFFFF" BorderThickness="1,1,1,1"
CornerRadius="4,4,4,4">
<!-- Внутренняя граница черная -->
<Border x:Name="border" Background="#7F000000" BorderBrush="#FF000000"
BorderThickness="1,1,1,1" CornerRadius="4,4,4,4">
<Grid>
<Grid.RowDefinitions>
<!-- Верхняя половинка кнопки -->
<RowDefinition Height="0.5*" />
<!-- Нижняя половинка кнопки -->
<RowDefinition Height="0.5*" />
</Grid.RowDefinitions>
<!-- Рисуем подсветку кнопки -->
<Border Opacity="0" HorizontalAlignment="Stretch" x:Name="glow" Width="Auto"
Grid.RowSpan="2" CornerRadius="4,4,4,4">
<Border.Background>
<!-- Задаем радиальный градиент со смещением -->
<RadialGradientBrush>
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.702" ScaleY="2.243" />
<SkewTransform AngleX="0" AngleY="0" />
<RotateTransform Angle="0" />
<TranslateTransform X="-0.368" Y="-0.152" />
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<!-- Цвета градиента в формате ARGB -->
<GradientStop Color="#B28DBDFF" Offset="0" />
<GradientStop Color="#008DBDFF" Offset="1" />
</RadialGradientBrush>
</Border.Background>
</Border>
<!-- Рисуем блик -->
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
Width="Auto" Grid.RowSpan="2" />
<Border HorizontalAlignment="Stretch" x:Name="shine"
Width="Auto" CornerRadius="4,4,0,0">
<Border.Background>
<LinearGradientBrush StartPoint="0.494,0.028" EndPoint="0.494,0.889">
<GradientStop Color="#99FFFFFF" Offset="0" />
<GradientStop Color="#33FFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
</Border>
</Border>
<!-- Задаем тригеры, описывающие реакцию на события мыши -->
<ControlTemplate.Triggers>
<!-- Кнопка мыши нажата -->
<Trigger Property="IsPressed" Value="True">
<Setter Property="Opacity" TargetName="shine" Value="0.4" />
<Setter Property="Background" TargetName="border" Value="#CC000000" />
<Setter Property="Visibility" TargetName="glow" Value="Hidden" />
</Trigger>
<!-- Курсор над объектом -->
<Trigger Property="IsMouseOver" Value="True">
<!-- Заходит на объект - вызываем анимацию Timeline1 -->
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource Timeline1}" />
</Trigger.EnterActions>
<!-- Уходит с объекта - вызываем анимацию Timeline2 -->
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource Timeline2}" />
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Grid>
<!-- Создаем экземпляр кнопки посредине окна -->
<Button x:Name="Btn1" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="176" Height="34"
Content="Мультимедийная кнопка" Foreground="#FFFFFFFF"
Template="{DynamicResource ClassButton}" />
</Grid>
</Window>
Запустите приложение
- должно получиться следующее
Выполните команду View/Other Windows/Document Outline
(либо щелкните на пиктограмме слева внизу в строке навигатора рабочей области),
чтобы открыть панель Document Outline (если она еще автоматически не
открылась)
Мы видим дерево всех дескрипторных элементов, составляющих проект. В Visual
Studio 2003 эта панель разрешала редактировать элементы, сейчас же она служит
только для просмотра дерева дескрипторных элементов или для быстрой навигации
по документу XAML. Обратите внимание, что корнем дерева объектов проекта является единственный класс,
в нашем случае, - класс Window. Возможны другие варианты корневого объекта,
например, Page. Но корень обязательно должен быть, причем, единственный. Он
и определяет тип приложения - Web или Windows.
Посмотрите XAML-дескриптор внутри контейнера <Grid>, там размещен экземпляр
кнопки Button, порожденный шаблоном ClassButton. Он и отображается на форме
проекта. Контейнер <Grid> XAML подобен контейнеру содержимого <body> в
HTML, которое отображается в окне (броузера или клиентского приложения). Все
компоненты панели Toolbox, которые мы будем перетаскивать на форму WPF в режиме
визуальной разработки интерфейса, будут представлены дескрипторами, размещенными
в контейнере <Grid>.
Если интерфейсную часть окна можно оформить через 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, который организует его подключение
к модели событий операционной системы с помощью метода Run(). Объект Application
отвечает за управление временем жизни приложения, отслеживает видимые окна,
освобождает ресурсы и контролирует глобальное состояние приложения. Метод Run()
запускает диспетчер среды исполнения, который начинает посылать события и сообщения
компонентам приложения.
В каждый момент времени может быть активен только один
объект Application и он будет работать до тех пор, пока приложение не завершится.
К исполняемому объекту Application можно получить доступ из любого места
приложения через статическое свойство Application.Current. Одна из основных
задач объекта Application состоит в том, чтобы контролировать время жизни процесса.
Конструирование объекта Application знаменует начало жизни приложения, а возврат
из его метода Run() - завершение приложения.
Время жизни приложения WPF (и объекта Application ) состоит из следующих этапов:
ApplicationRun()Application.StartupWindow (или Page ) и приложение выполняет работуApplication.Shutdown()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), и также можно конструировать пользовательский интерфейс через любую часть. Но кодировать события и тонкие настройки возможно только через кодовую часть.
В данном упражнении мы будем говорить об окнах WPF и одновременно иллюстрировать сказанное на ряде примеров. Окна создаются не как самоцель - это удобный способ инкапсуляции (сокрытия, упаковки) некоторой функциональности. Окно представляет собой самый верхний уровень взаимодействия с пользователем (завершенной целостности) и не может быть частью другого окна.
Окна бывают модальными
и немодальными. Модальное окно блокирует все другие окна приложения до его
закрытия, переключая на себя взаимодействие приложения с операционной системой
(если не создано в отдельном потоке). Окна бывают
Для удобства все примеры упражнения мы упакуем в отдельные окна, которые будем вызывать из главного окна приложения.
Добавьте к решению 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 также, как и объект Application приложения,
имеет этапы своей жизни:
Window.Initialized - окно инициализировало декларативные
элементыWindow.Activated - окно получило фокус вводаWindow.Deactivated - окно теряет фокус вводаWindow.Loaded - окно построено, но еще не отображеноWindow.ContentRenderer - окно только-что отображено
на экранеWindow.Closing - поступила требование закрыть окно,
которое еще можно отменитьWindow.Closed - окно разрушено и не подлежит восстановлению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 окна
Открытие окна в немодальном режиме может выполняться любым из двух равноценных способов:
wnd1.Show();wnd1.Visibility = Visibility.Visible;Если окну назначить владельца через свойство Owner, то при его открытии
в немодальном режиме оно будет размещаться всегда поверх владельца, а также
сворачиваться и закрываться вместе с ним. Такое окно не мешает владельцу получать
фокус ввода. Обычно владельца назначают окнам поиска и замены, инструментальным
окнам.
Одно и то же приложение может создавать несколько окон, которые одновременно могут быть открыты. Если этим окнам не назначен владелец, то при закрытии порождающего окна они так и останутся открытыми. Это можно проверить и на последнем примере, если выполнить следующее
LifeEvents() файла Window0.axml.cs код модального открытия окна wnd1.ShowModal() ;
на wnd1.Show() ;Window0 открыть несколько экземпляров окна Window1, затем закрыть
окно Window0После таких действий все дочерние окна остаюся открытыми и их нужно закрывать вручную (если только мы их запускали не из под оболочки). К тому же пиктограммы окон не отображаются в панели задач и стоит нам перекрыть экран другим окном, то эти окна придется закрывать либо, предварительно свернув все другие окна, либо через диспетчер задач.

Такое поведение не совсем хорошее, поэтому разработчики платформы WPF предусмотрели
в объекте Application соответствующие средства. Мы их рассмотрим в данном
упражнении.
Добавьте к решению
новый WPF-проект с именем WpfApp3 и назначьте
его стартовым
В панели Solution
Explorer удалите из проекта WpfApp3 файл с автоматически
созданным именем Window1.xaml и добавьте новый файл с именем WindowList.xaml (чтобы не переименовывать во многих местах)
Откройте файл App.xaml проекта WpfApp3 и
поменяйте значение параметра StartupUri объекта Application на имя файла нового стартового окна<Application x:Class="WpfApp3.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="WindowList.xaml"
>
</Application>
Откройте файл WindowList.xaml в режиме View
XAML и настройте стартовое окно следующим образом<Window x:Class="WpfApp3.WindowList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowList"
SizeToContent="WidthAndHeight"
MinWidth="200"
>
<StackPanel>
<Button Click="NewWindowClicked">Создать новое окно</Button>
<Button Click="ListOpenWindows">Список открытых окон</Button>
</StackPanel>
</Window>
Проследите, чтобы одновременно
были созданы зарегистрированные в кнопках обработчики
Модифицируйте файл WindowList.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.Shapes;
namespace WpfApp3
{
/// <summary>
/// Interaction logic for WindowList.xaml
/// </summary>
public partial class WindowList : Window
{
static int createCount;
public WindowList()
{
InitializeComponent();
// Определение заголовка окна
this.Title = "Окно № " + (createCount++).ToString();
}
private void NewWindowClicked(object sender, RoutedEventArgs e)
{
new WindowList().Show();
}
private void ListOpenWindows(object sender, RoutedEventArgs e)
{
StringBuilder sb = new StringBuilder();
foreach (Window openWindow in Application.Current.Windows)
sb.AppendLine(openWindow.Title);
MessageBox.Show(sb.ToString(), "Открытые окна приложения");
}
}
}
Запустите приложение
- оно хранит и выдает список открытых в текущий момент окон
Однако все окна, открытые приложением, приходится по-прежнему закрывать вручную. Для решения этой проблемы есть два пути:
Application.Current.MainWindow ссылку на это окноApplication.Current.Shutdown()Какой из этих двух вариантов будет работать, определяет свойство Application.Current.ShutdownMode.
Оно может принимать одно из следующих значений одноименного перечисления:
ShutdownMode.OnLastWindowClose - закрывать приложение вместе с закрытием
последнего окна (установлено по умолчанию)ShutdownMode.OnMainWindowClose - закрывать приложение вместе с закрытием
главного окнаShutdownMode.OnExplicitShutdown - закрывать приложение только тогда, когда
явно вызван метод Shutdown()Приложение в режиме ShutdownMode.OnExplicitShutdown может закрыться только
методом Shutdown(), но и в двух предыдущих режимах метод Shutdown() работает
всегда.
Испытаем оба способы.
Для разнообразия сделаем главным окно под номером 3, а во все окна добавим
кнопку вызова метода Shutdown().
Откройте файл WindowList.xaml в
режиме View XAML и добавьте к стартовому окну еще одну кнопку<Window x:Class="WpfApp3.WindowList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowList"
SizeToContent="WidthAndHeight"
MinWidth="200"
>
<StackPanel>
<Button Click="NewWindowClicked">Создать новое окно</Button>
<Button Click="ListOpenWindows">Список открытых окон</Button>
<Button Click="AllCloseWindows">Закрыть все окна</Button>
</StackPanel>
</Window>
Проследите, чтобы одновременно
был создан зарегистрированный в кнопке обработчик
Модифицируйте файл WindowList.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.Shapes;
namespace WpfApp3
{
/// <summary>
/// Interaction logic for WindowList.xaml
/// </summary>
public partial class WindowList : Window
{
static int createCount;
public WindowList()
{
InitializeComponent();
// Определение заголовка окна и назначение главного окна
if (createCount == 3)
{
Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
Application.Current.MainWindow = this;
this.Title = "Главное окно № " + (createCount++).ToString();
}
else
this.Title = "Окно № " + (createCount++).ToString();
}
private void NewWindowClicked(object sender, RoutedEventArgs e)
{
new WindowList().Show();
}
private void ListOpenWindows(object sender, RoutedEventArgs e)
{
StringBuilder sb = new StringBuilder();
foreach (Window openWindow in Application.Current.Windows)
sb.AppendLine(openWindow.Title);
MessageBox.Show(sb.ToString(), "Открытые окна приложения");
}
private void AllCloseWindows(object sender, RoutedEventArgs e)
{
//Application.Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
Application.Current.Shutdown();// Закрывает при любом режиме
}
}
}
Запустите приложение
и убедитесь, что оно в любом месте закрывается методом Shutdown(),
а также при закрытии третьего окнаЕсли установить режим ShutdownMode.OnExplicitShutdown, то приложение
можно завершить только методом Shutdown().
Пользователи среды разработки (программисты) делятся на две категории: те,
кто разрабатывает законченные приложения и те, кто разрабатывает элементы управления,
в том числе - интерфейсные (визуальные). Последние конструируют из библиотечных
элементов укрупненные блоки, которые можно использовать при разработке интерфейса
окон: пользовательские (user control) и нестандартные (
Таким образом, пользовательские элементы управления (user control) - это
способ инкапсуляции (упаковки) частей графического интерфейса. Нестандартные
графические элементы (
В качестве базового для пользовательского элемента управления берется библиотечный
класс ContentControl или производный от него UserControl
из пространства имен System.Windows.Controls. В этом упражнении мы проиллюстрируем
создание и применение пользовательских элементов управления на примере инкапсуляции
кнопки Button.
Добавьте к решению
новый WPF-проект с именем WpfApp4 и назначьте его стартовым
В панели Solution Explorer
выделите узел проекта WpfApp4, в главном меню оболочки выполните
команду Add User Control и добавьте к проекту новый файл с именем MyUserControl.xaml
Модифицируйте интерфейсную
часть <UserControl x:Class="WpfApp4.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Button Click="Button_Click">Моя кнопка</Button>
</UserControl>
Модифицируйте кодовую
часть 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 WpfApp4
{
/// <summary>
/// Interaction logic for MyUserControl.xaml
/// </summary>
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Привет всем!", "Элемент UserControl");
}
}
}
Откомпилируйте (только
откомпилируйте!) проект WpfApp4, чтобы создать пользовательский элемент
для видимости его подсказчиком кода IntelliSense в файле окна
Откройте на редактирование
в режиме XAML файл Window1.xaml и измените его дескрипторный код так<Window x:Class="WpfApp4.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:My="clr-namespace:WpfApp4"
Title="Упражнение 4"
Width="200"
SizeToContent="Height"
WindowStartupLocation="CenterScreen"
>
<StackPanel>
<My:MyUserControl Margin="1"/>
<My:MyUserControl Margin="1"/>
</StackPanel>
</Window>
В дескриптор окна Window мы добавили пользовательское пространство имен WpfApp4 с
псевдонимом My, чтобы окно увидело пользовательский элемент. Мы жестко задали
ширину окна и сказали, чтобы по высоте окно подстраивалось под свое содержимое.
Мы установили начальное положение окна в центре экрана. В клиентскую область
окна мы поместили контейнер с двумя экземплярами пользовательского элемента.
Запустите на выполнение
проект WpfApp4 и испытайте работу простого пользовательского элемента
в составе окна приложения
WPF поддерживает переходы в стиле веб-обозревателя, которые могут использоваться в приложениях двух типов: автономных приложениях и XBAP ( XAML browser applications - приложения обозревателя XAML)
Платформа WPF имеет средства создавать страницы, которые в некоторых
случаях могут быть более привычны пользователю, чем оконные приложения. В страничных
приложениях содержимое страниц встраивается в специальный навигационный каркас,
поддерживающий навигационные ссылки и журнал навигации. Корневым узлом
в них является не класс Window, а производный от него класс NavigationWindow,
который добавляет стандартный интерфейс навигации и всю необходимую инфраструктуру.
Класс NavigationWindow имеет доступ к тем же самым средствам уровня приложения,
что и Window.
Добавьте к решению
новый проект с именем WpfApp5 и назначьте его стартовым
Удалите автоматически
созданный мастером файл Window1.xaml и добавьте к проекту вместо него новый
файл с именем NavExample.xaml по тому же оконному шаблону
Откройте файл App.xaml и скорректируйте атрибут StartupUri="NavExample.xaml"
Выполните проект WpfApp5,
чтобы убедиться в отсутствии ошибок
Откройте файл NavExample.xaml и скорректируйте его дескрипторный код так<NavigationWindow x:Class="WpfApp5.NavExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Упражнение 5"
Height="300"
Width="300"
WindowStartupLocation="CenterScreen"
>
</NavigationWindow>
Откройте
файл NavExample.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.Shapes;
using System.Windows.Navigation;
namespace WpfApp5
{
/// <summary>
/// Interaction logic for NavExample.xaml
/// </summary>
public partial class NavExample : NavigationWindow
{
public NavExample()
{
InitializeComponent();
//this.Navigate(new Page1());
}
}
}
Запустите проект -
пока мы видим пустой контейнер с заготовкой навигационного узла
Содержимое навигационного узла должно быть представлено классом, производным
от библиотечного класса Page. Создадим три пробные страницы содержимого
и подключим их к навигационному узлу с помощью метода Navigate().
Добавьте к проекту
новый элемент Page с именем Page1.xaml
Отредактируйте дискрипторную
часть файла Page1.xaml следующим образом<Page x:Class="WpfApp5.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel>
<TextBlock TextAlignment="Center" FontSize="24">Страница 1</TextBlock>
<TextBlock></TextBlock>
<TextBlock>
<Hyperlink Click="LinkClicked">На страницу 2</Hyperlink>
</TextBlock>
</StackPanel>
</Page>
Отредактируйте кодовую
часть - файл Page1.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 WpfApp5
{
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
}
private void LinkClicked(object sender, RoutedEventArgs e)
{
this.NavigationService.Navigate(new Page2());
}
}
}
Добавьте к проекту
новый элемент Page с именем Page2.axml
Отредактируйте
дискрипторную часть файла Page2.axml следующим образом<Page x:Class="WpfApp5.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page2"
>
<StackPanel>
<TextBlock TextAlignment="Center" FontSize="24">Страница 2</TextBlock>
</StackPanel>
</Page>
Добавьте в файл NavExample.xaml
атрибут Source, подключающий при запуске каркаса начальную страницу содержимого Page1.xaml (вместо этого можно было бы добавить в конструктор класса NavExample
кодовой части каркаса закомментированную строку создания экземпляра типа this.Navigate(new
Page1()); )<NavigationWindow x:Class="WpfApp5.NavExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Упражнение 5"
Height="300"
Width="300"
WindowStartupLocation="CenterScreen"
Source="Page1.xaml"
>
</NavigationWindow>
Запустите проект на
выполнение и пощелкайте на ссылках - пока все работаетМы создали каркас и две пустые страницы, которые ничего не делают. Каждая
страница является автономной, даже если наполнить ее элементами управления.
При переходе между страницами нужно научиться передавать информацию от странице
к странице, т.е. хранить их состояние. Должен быть общий почтовый ящик, не
зависящий от существования страниц, в котором бы эта информация хранилась.
В WPF для передачи данных между страницами можно использовать словарь (массив
пар "ключ-значение") Application.Current.Properties или
'зашивать' информацию прямо в объект новой страницы.
Продолжим развитие упражнение. Дополним первую страницу текстовым полем, через которое пользователь введет свое имя, а на второй странице выведем приветствие с этим именем через текстовую метку.
Добавьте к странице Page1 именованное текстовое поле с меткой следующим образом<Page x:Class="WpfApp5.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1"
>
<StackPanel>
<TextBlock TextAlignment="Center" FontSize="24">Страница 1</TextBlock>
<TextBlock></TextBlock>
<Label>Введите свое имя: </Label>
<TextBox Name="nameBox" Width="200"></TextBox>
<TextBlock></TextBlock>
<TextBlock>
<Hyperlink Click="LinkClicked">На страницу 2</Hyperlink>
</TextBlock>
</StackPanel>
</Page>
Объекту TextBox мы присвоили имя, чтобы можно было обращаться к нему из кода.
Измените кодовую часть
страницы Page1 следующим образом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 WpfApp5
{
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
}
private void LinkClicked(object sender, RoutedEventArgs e)
{
Page2 page2 = new Page2();
page2.Message = nameBox.Text + " !!!";// Зашиваем информацию в объект страницы
this.NavigationService.Navigate(page2);
}
}
}
Добавьте на страницу Page2 именованную текстовую метку и гиперссылку для перехода на Page3, а
также подпишитесь на событие Loaded страницы и на событие Click гиперссылки<Page x:Class="WpfApp5.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page2"
Loaded="Page_Loaded"
>
<StackPanel>
<TextBlock TextAlignment="Center" FontSize="24">Страница 2</TextBlock>
<TextBlock></TextBlock>
<TextBlock>Приветствуем Вас дорогой </TextBlock>
<Label Name="nameLabel"></Label>
<TextBlock Margin="0,10"> <!--Отступ сверху-->
<Hyperlink Click="LinkClicked">На страницу 3</Hyperlink>
</TextBlock>
</StackPanel>
</Page>
Объекту Label мы присвоили имя, чтобы можно было обращаться к нему
из кода.
Добавьте в кодовую
часть страницы Page2 публичное свойство, код присвоения текстовой
метке переданного текста в обработчике события Loaded и код перехода на следующую
страницу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 WpfApp5
{
public partial class Page2 : Page
{
public Page2()
{
InitializeComponent();
}
string message;
public string Message
{
set { message = value; }
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
nameLabel.Content = message;
}
private void LinkClicked(object sender, RoutedEventArgs e)
{
Page3 page3 = new Page3();
this.NavigationService.Navigate(page3);
}
}
}
Запустите приложение
- информация передается, но только по щелчку на ссылкеПо щелчку на кнопке навигации свежая информация из текстового поля не передается, потому что берется из журнала истории.
Заполните разметку
страницы Page3 следующим кодом<Page x:Class="WpfApp5.Page3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page3">
<StackPanel>
<!--Заголовок контекста страницы-->
<TextBlock TextAlignment="Center" FontSize="24">Страница 3
<TextBlock.Margin>0,0,0,10</TextBlock.Margin>
</TextBlock>
<!--Первая кнопка-->
<Button Content="Push Me!" FontSize="22" Height="50" Click="Button_Click">
<Button.Effect>
<DropShadowEffect />
</Button.Effect>
</Button>
<!--Вторая кнопка-->
<Button FontSize="22" Height="50" Margin="0,10" Click="Button_Click">
Кликни меня
<Button.Effect>
<DropShadowEffect />
</Button.Effect>
<Button.Foreground>
<LinearGradientBrush StartPoint="1,0" EndPoint="0,0">
<GradientStop Color="Red" Offset="0" />
<GradientStop Color="Orange" Offset=".17" />
<GradientStop Color="Yellow" Offset=".33" />
<GradientStop Color="Green" Offset=".5" />
<GradientStop Color="CornflowerBlue" Offset=".67" />
<GradientStop Color="Blue" Offset=".84" />
<GradientStop Color="BlueViolet" Offset="1" />
</LinearGradientBrush>
</Button.Foreground>
<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Red" Offset="0" />
<GradientStop Color="Orange" Offset=".17" />
<GradientStop Color="Yellow" Offset=".33" />
<GradientStop Color="Green" Offset=".5" />
<GradientStop Color="CornflowerBlue" Offset=".67" />
<GradientStop Color="Blue" Offset=".84" />
<GradientStop Color="BlueViolet" Offset="1" />
</LinearGradientBrush>
</Button.Background>
</Button>
</StackPanel>
</Page>
Обработчик события Click в дескрипторах кнопок нужно прописывать вручную,
чтобы оболочка создала их заготовки в файле кодовом части.
Прежде, чем заполнить кодовую часть страницы Page3, мы добавим к проекту новую
форму, чтобы показать
совместную работу технологий WPF и Windows Forms. В обработчик кнопок поместим
код запуска формы.
Добавьте к проекту WpfApp5 новую форму Form1
Поместите на форму
из панели Toolbox элемент DataGridView, установите его свойство Dock=Fill
и добавьте через интеллектуальный дескриптор ( SmartTag ) пару столбцов
Общий обработчик кнопок
в кодовой части Page3 заполните такprivate void Button_Click(object sender, RoutedEventArgs e)
{
Form1 frm = new Form1();
frm.ShowInTaskbar = false;// Не показывать кнопку формы в панели задач
frm.Show();
}
Запустите проект и
полюбуйтесь на дизайн новой страницы, а также убедитесь, что по щелчку запускается
форма Form1 с интерфейсом другой технологии
Этот пример иллюстирирует возможность совместного использования интерфейса Windows Forms и интерфейса WPF, но только на уровне отдельных окон. Смешивать интерфейсные компоненты разных технологий в одном окне нельзя, они построены на разных принципах. Но на уровне бизнес-логики вся мощь библиотеки .NET Framework и языка C# остается в распоряжении программиста.
Если программист реализует пользовательский интерфейс по технологии WPF, то он должен помнить, что WPF поддерживается только начиная с Windows XP (SP2), а в Windows 95, Windows 98, Windows 2000 - не поддерживается.

Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.