01_Березина_Введение_XAML

advertisement
Литература
1. Мэтью Мак-Дональд . Windows Presentation Foundation в .NET 3.5 с
примерами на C# 2008 для профессионалов - Изд. Вильямс, 2008.
2. Крис Андерсон. Основы Windows Presentation Foundation. – ДМК
Пресс, СПб, 2008.
3. Петцольд Ч. Microsoft Windows Presentation Foundation. Базовый
курс. - Изд. Microsoft Press. Русская редакция, СПб.: Питер, 2008.
Программные модели пользовательского
интерфейса
1985
Windows API ( Windows 1.0)
1990 Windows API ( Windows 3.0)
1992
MFC (Microsoft Foundation Classes) – библиотека классов C++
2001
Windows Forms в .NET Framework 1.0
2006
WPF (Windows Presentation Foundation) в .NET Framework 3.0
Цели разработки Windows Presentation Foundation
 Основная цель разработки WPF – создать новую унифицированную
платформу, которая заменила бы всю инфраструктуру создания приложений на
стороне клиента и использовала бы лучшее из Win32 и Web.
 В начале 2000-х Microsoft поддерживала четыре платформы для создания
пользовательского интерфейса User32/GDI32, Ruby (формы Visual Basic), Trident
(отображение web-страниц в приложениях) и Windows Forms, в основе которых
лежали разные модели программирования.
 Цели при проектировании WPF:
• создать платформу для развитой презентации;
• создать платформу, поддерживающую взаимодействие кода и
декларативной модели программирования;
• стереть границы между Windows и Web.
WPF- Windows Presentation Foundation
Windows Presentation Foundation
WindowsForms
PresentationFramework
Common Language Runtime
Windows 7
Windows Vista
PresentationCore
milcore
DirectX
Windows XP Windows Server 2003
 Весь вывод происходит через DirectX – интерфейс аппаратно-ускоренной
графики.
Windows Forms и Win32 API
 WindowsForms - управляемый API в .NET Framework 1.0, 2.0, 3.x для
создания пользовательского интерфейса локальных приложений. WindowsForms
- это фактически управляемый слой над User32 и GDI+.
 Классы WindowsForms поддерживают все элементы пользовательского
интерфейса Win32.
 Некоторые классы описывают элементы управления, работающие только в
.NET Framework.
 Большая часть типов WindowsForms определена в пространстве имен
System.Windows.Forms и во вложенных пространствах имен.
Иерархия классов Windows Forms
System.Object
MarshalByRefObject
Component
Control
FolderBrowserDialog
ContextMenu
ContainerControl
ColorDialog
MainMenu
Form
FontDialog
MenuItem
PrintDialog
CheckButton
RadioButton
PageSetupDialog
TextBoxBase
TextBox
FileDialog
RichTextBox
ListControl
ListBox
Menu
ScrollableControl
ButtonBase
Button
CommonDialog
ComboBox
ListView
TreeView
DataGrid
DateTimePicker
.......
OpenFileDialog
SaveFileDialog
Классы Windows Presentation Foundation
System.Object
DispatcherObject
Application
DependencyObject
NavigationService
FrameworkTemplate
Visual
ContentElement
UIElement
FrameworkContentElement
Style
FrameworkElement
Page
Shape
TextBlock
ContentControl
Panel
Control
RangeBase
TextBoxBase
Frame
Slider
TextBox
Window
ProgressBar
RichTextBox
NavigationWindow
ButtonBase
Grid
ItemsControl
MenuBase
Menu
ContextMenu
HeaderedItemsControl
MenuItem
Button
Toolbar
Selector
RepeatButton
TabControl
ToggleButton
CheckBox
Canvas
RadioButton
ListBox
ListView
TreeView
ComboBox
WPF и XAML
 Одна из задач, которая была решена при проектировании и реализации WPF, разделение работы между дизайнерами и программистами.
 Решение состоит в разделении исходного кода WPF-приложения на две части:
• декларативное описание пользовательского интерфейса с использованием языка
разметки XAML (EXtensible Application Markup Language );
• код на языке программирования, например C#, содержащий обработку событий.
Для компиляции WPF-приложений обычно используется Microsoft Build Engine (MSBuild)
–технология, включенная в .NET Framework 3.x в виде набора сборок.
Компиляция WPF приложений
 При компиляции XAML файлы разбираются (parsed) и преобразуются в коды на языке
BAML ( Binary Application Markup Language), которые встраиваются как ресурс в
исполняемый файл.
 Код BAML компактнее исходного XAML кода и при выполнении его загрузка
выполняется быстрее, чем загрузка XAML файла.
 При компиляции для каждого XAML файла создается файл с кодом на языке
программирования, содержащий частичное (partial) объявление класса для элемента
верхнего уровня в файле разметки.
 В общем случае компиляция XAML файлов осуществляется в два прохода.
• Сначала компилируются только те XAML файлы, которые не содержат ссылки на
локально-определенные типы (типы, определенные в данном проекте), так как они
существуют только в виде исходного кода и еще не были скомпилированы.
• XAML файлы со ссылками на локально-определенные типы компилируются при
втором проходе компилятора.
 Вся необходимая для работы MSBuild информация об исходных файлах, ссылках на
зависимые сборки и конфигурация приложения находится в файлах проекта MSBuild - XML
файлах, подчиняющихся схеме MSBuild.
Элементы XAML
 Элементы XAML отображаются на типы Microsoft .NET, атрибуты элементов XAML на
члены этих типов.
 Начальное состояние объекта ( object instance) базируется на поведении конструктора
без параметров (default constructor).
 В примере 1 фрагмент кода XAML содержит элемент Button, отвечающий классу
System.Windows.Controls.Button. С использованием синтаксиса атрибутов XAML
свойствам Height, HorizontalAlignment, Margin и Name элемента Button присвоены
значения.
<Button Height="23" HorizontalAlignment="Center" Margin="13,0,0,56"
Name="button1“ > Get </Button>
 В примере 2 код XAML содержит элемент Window, отвечающий классу
System.Windows.Window. Элемент Window содержит элемент Grid, который в свою
очередь содержит элементы Button и TextBox.
<Window x:Class="Wpf_Sample1.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">
<Grid>
<Button Height="23" HorizontalAlignment="Center" Margin="13,0,0,56“
Name="button1" VerticalAlignment="Bottom" Width="75">Get</Button>
<TextBox Height="23" Margin="14,68,18,0" Name="textBox1"
VerticalAlignment="Top" />
</Grid>
</Window>
Пространства имен XAML
 Два пространства имен – пространство имен XAML и пространство имен WPF присутствуют во всех WPF документах:
<Window x:Class="Wpf_Sample1.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">
<Grid>
</Grid>
</Window>
 Корневой элемент Window содержит атрибуты xmlns и xmlns:x. Эти атрибуты указывают
XAML процессору пространства имен, в которых находятся определения элементов, на
которые ссылается разметка.
Атрибут xmlns указывает на пространство имен по умолчанию. Элементы из этого
пространства используются в разметке без префикса.
 Синтаксический анализатор использует атрибут Class для создания класса,
производного от типа, совпадающего именем элемента ( Window в данном примере).
Атрибут Class указан с префиксом x: , что означает, что это имя находится в пространстве
имен XAML.
Пространства имен XAML и WPF
 Использование двух пространств имен объясняется тем, что XAML – это стандарт языка,
а WPF – одна из реализаций, которая использует XAML как язык.
 Реализация WPF резервирует пространство имен по умолчанию для собственного API.
Есть соглашение использовать префикс x: для общих конструкций XAML.
 Пространству имен, определенному в любой сборке CLR, можно поставить в
соответствие имя пространства имен в разметке. В примере пространству имен Labs,
определенному в сборке UserLibrary, ставится в соответствие пространство имен в
разметке с префиксом my:
xmlns:my="clr-namespace:Labs;assembly=UserLibrary”
 Классы, определенные в сборке LabsLibrary, можно использовать в разметке, указав их с
префиксом my:
<Window x:Class="Wpf_Sample1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:Labs;assembly=UserLibrary”
Title="Window1" Height="300" Width="300">
<Grid>
</Grid>
</Window>
Регистр в XAML
 XAML чувствителен к регистру. Элементы-объекты, имена свойств элементов и имена
атрибутов должны с учетом регистра отвечать соответствующим именам в сборках CLR.
 Значения атрибутов не всегда чувствительны к регистру, например, преобразователь
типа для булевских значений разрешает использовать как true, так и True.
Правила обработки пробелов в XAML
 В XAML(как и в XML) символами-пробелами (whitespace) считаются пробел(Unicode
0020), символ перевода строки (\n - Unicode 000A) и символ табуляции (\t - Unicode 0009).
 По умолчанию синтаксический анализатор XAML сначала все символы-пробелы
заменяет пробелами, а затем все подряд идущие пробелы заменяет одним пробелом.
 Можно отказаться от обработки пробелов по умолчанию, указав атрибут
xml:space="preserve” в элементах, для которых необходимо сохранить символы-пробелы.
 В примере текст на кнопке button1 выводится в одну строку с одним пробелом между
словами Test и Button, а текст на кнопке button2 в две строки с сохранением всех
пробелов.
<Button Height="23" Margin="34,0,31,80" Name="button1"
VerticalAlignment="Bottom“> Test 
 Button</Button>
<Button Height="41" Margin="34,0,31,8" Name="button2"
VerticalAlignment="Bottom" xml:space="preserve"> Test 

Button</Button>
Код(code-behind) и XAML
 Обычно WPF-приложение содержит как разметку( XAML код), так и код C# (codebehind).
Обычно XAML полностью описывает интерфейс пользователя, а обработчики событий
находятся в коде C#, их имена указываются в разметке как значения атрибутов.
Обработчики вызываются на стадии выполнения, когда возникают события.
 Соответствие разметки и кода C# устанавливается путем указания в корневом элементе
XAML пространства имен и класса в атрибуте x:Class.
 С объектами, которые создаются на основе определений в XAML, по умолчанию не
связывается переменная. Для этой цели определен атрибут x:Name, с помощью которого с
объектом можно связать переменную и использовать ее в коде C#.
 Некоторые WPF-классы имеют свойство Name, которое можно использовать как
эквивалент атрибута x:Name.
 Класс XamlReader с методом Load дает возможность загрузить код XAML во время
выполнения. В результате компиляции будет создано дерево объектов, которое можно
использовать как значение свойства ранее созданного в приложении объекта. Это
возможно только в full-trust приложениях.
Атрибуты XAML и значения свойств объектов WPF
 Значением атрибута XAML должна быть строка символов, заключенная в двойные
кавычки.
 Значение обрабатывается XAML-процессором и определяется типом свойства CLR.
• для примитивных типов используется принятое по умолчанию преобразование типа
string к данному типу;
• для свойства, которое имеет тип перечисление(enumeration), строка трактуется как
имя элемента перечисления;
• в остальных случаях значение атрибута должно быть обработано преобразователем
типа (type converter).
 Пример. В классе Button определены свойства
public double Height { get; set; }
public VerticalAlignment VerticalAlignment { get; set; }
 В разметке свойству Height типа double присвоено значение 23, а свойству
VerticalAlignment, которое имеет тип перечисления VerticalAlignment, присвоено значение
перечисления Bottom.
<Button Height="23" HorizontalAlignment="Center" Margin="13,0,0,56"
Name="button1" VerticalAlignment="Bottom" Width="75">Get</Button>
Преобразователи типов (TypeConverters)
 Преобразователь типа (type converter) определяется либо для конкретного свойства
класса CLR, которому присваивается значение, либо для типа этого свойства.
 Преобразователь принимает строку и как результат возвращает объект типа, который
имеет свойство CLR.
<Button Height="23" HorizontalAlignment="Center" Margin="13,0,0,56"
Name="button1" VerticalAlignment="Bottom" Width="75">Get</Button>
 Свойство Margin класса Button имеет тип Thickness.
public Thickness Margin { get; set; }
 Со структурой Thickness связан преобразователь ThicknessConverter, который
преобразует строку к типу Thickness.
Преобразователи типов (TypeConverters) в WPF
 Преобразователь типа связывается с типом или конкретными свойствами типа с
помощью атрибута CLR TypeConverterAttribute, которому передается как параметр имя
типа, который будет использоваться как преобразователь.
 Так структура Thickness объявлена с атрибутом CLR TypeConverterAttribute, в котором в
качестве преобразователя указан класс ThicknessConverter.
[TypeConverterAttribute(typeof(ThicknessConverter))]
public struct Thickness : IEquatable<Thickness>
 Класс-преобразователь типа должен быть производным от класса TypeConverter и
может переопределять методы, выполняющие преобразования, ( например, ConvertTo и
ConvertFrom) и булевские свойства CanConvertTo и CanConvertFrom , предоставляющие
информациею о том, возможны ли преобразования.
public Object ConvertFrom( Object value );
public bool CanConvertTo( Type destinationType );
public bool CanConvertFrom( Type sourceType );
public bool CanConvertTo( Type destinationType );
Элемент-свойство (property element)
 Для установки значений свойств, которые являются ссылками на объекты ( возможно
имеющие свой набор свойств) может использоваться синтаксис элемент-свойство (property
element).
 Синтаксис элемента-свойство:
<TypeName.Property> content </TypeName.Property>
 Обычно content – это объект, который принимается как значение свойства.
 В примере синтаксис элемент-свойство используется для установки значения свойства
ContextMenu класса ListBox.
public ContextMenu ContextMenu { get; set; }
 В разметке как значение свойства ContextMenu используется элемент <ContextMenu>.
<ListBox Margin="44,54,48,60" Name="listBox1">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="_File"/>
<MenuItem Header="_Edit"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
Синтаксис элемент-свойство для коллекций
 Для свойства, которое является коллекцией, тип коллекции в разметке не указывается .
Элементы коллекции размещаются как один или несколько дочерних элементов.
 В процессе загрузки каждый элемент инициализируется (конструктором без параметров)
и добавляется в коллекцию с помощью метода Add.
 XAML–процессор для WPF поддерживает коллекции, реализующие интерфейсы IList и
IDictionary.
 Расширения XAML поддерживают работу с массивами.
 В примере свойство Items класса ContextMenu, представляющее собой коллекцию
ItemCollection элементов типа MenuItem, инициализируется с использованием синтаксиса
элемент-свойство для коллекций.
<ListBox Margin="44,54,48,60" Name="listBox1">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="_File"/>
<MenuItem Header="_Edit"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
Обработчики событий
 Обычно WPF-приложение содержит как XAML код, так и код на C#( code-behind).
 Обработчики событий обычно находятся в коде C#, их имена указываются в разметке
как значения атрибутов.
 В примере в разметке с событием Closing для окна связан обработчик Window_Closing, а
с событием Click для кнопки - обработчик button1_Click.
<Window x:Class="Wpf_Sample1.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" Closing="Window_Closing">
<Grid>
<Button Height="23" HorizontalAlignment="Center" Margin="13,0,0,56"
Name="button1" VerticalAlignment="Bottom" Width="75"
Click="button1_Click">Get</Button>
</Grid>
</Window>
 Обработчики должны иметь тип, отвечающий событию.
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
MessageBoxResult res = MessageBox.Show("Закрыть окно?", "", MessageBoxButton.YesNo);
if (res == MessageBoxResult.No) e.Cancel = true;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show ("Pressed button Get“);
}
Расширения языка разметки (Markup extentions)
 По умолчанию XAML-процессор интерпретирует значения атрибутов как литеральные
строки и выполняет преобразование строк в объекты с помощью преобразователей типов.
 Расширения языка разметки (markup extentions ) позволяют выполнить более сложную
инициализацию:
• использовать ссылку на ранее созданный или статический объект;
• указать в конструкторе объекта значения параметров, отличные от значений по
умолчанию;
• отложить обработку значений до времени выполнения, передав ее классу (backing
class).
 Расширения разметки заключаются в фигурные скобки.
 Наиболее часто используемые расширения языка разметки в WPF - Binding,
StaticResource и DynamicResource.
Расширения языка разметки. Пример
 В следующем примере контекстное меню определено как ресурс с ключом
MyContextMenu_1 и затем используется как значение для свойства ContextMenu элемента
ListBox
<Window x:Class="WPF_ContextMenu.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="381" Width="484" Loaded="Window_Loaded">
<Window.Resources>
<ContextMenu x:Key="MyContextMenu_1">
<MenuItem Header="Add" Click="Add_MenuItem_Click"></MenuItem>
<MenuItem Header="New" Command="ApplicationCommands.New"></MenuItem>
</ContextMenu>
</Window.Resources>
<Grid >
<ListBox Margin="19,18,208,0" Name="listBox1" Height="107"
VerticalAlignment="Top" ContextMenu="{StaticResource MyContextMenu_1}"/>
</Grid>
</Window>
Контентный синтаксис (Content Syntax) в XAML
 Контентный синтаксис XAML допустим только для классов CLR, имеющих атрибут
ContentPropertyAttribute в объявлении.
 В параметре атрибута ContentPropertyAttribute указывается имя свойства класса CLR,
которое XAML-процессор трактует как содержимое (content) для данного класса ( включая
производные классы).
 Например, класс Button имеет атрибут ContentPropertyAttribute, унаследованный от
базового класса ContentControl.
[ContentPropertyAttribute("Content")]
public class ContentControl : Control, IAddChild
 Класс ListBox имеет атрибут ContentPropertyAttribute, унаследованный от базового
класса ItemsControl.
[ContentPropertyAttribute("Items")]
public class ItemsControl : Control, IAddChild
XAML-процессор любой дочерний элемент или внутренний текст между открывающим и
закрывающим тэгом элемента трактует как содержимое элемента. Исключение
составляют тэги элементов-свойств, которые обрабатываются в первую очередь и не
рассматриваются как содержимое элемента.
 Контентное свойство объекта имеет конкретный тип. Контентным типом может быть типколлекция, но в любом случае содержимое -это единственный объект.
Контентный синтаксис в XAML. Пример
 Значение контентного свойства XAML дожно быть непрерывным, то есть должно
находиться целиком до или целиком после любого другого элемента-свойства.
<ListBox Margin="20,54,19,0" Name="listBox1" Height="64" VerticalAlignment="Top">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="_File"/>
<MenuItem Header="_Edit"/>
</ContextMenu>
</ListBox.ContextMenu>
<ListBoxItem>Green</ListBoxItem>
<ListBoxItem>White</ListBoxItem>
<ListBoxItem>Red</ListBoxItem>
</ListBox>
 В примере сначала инициализруется свойство ContextMenu объекта ListBox. В классе
ContextMenu контентным является свойство Items, представляющее собой коллекцию.
 Затем инициализируетя контентное свойство Items класса ListBox, также
представляющее собой коллекцию.
 Каждый элемент коллекции является объектом типа ListBoxItem, который наследует
контентное свойство Content от базового класса ContentControl.
Download