Разделение окна на два столбца Создайте в контейнере два столбца. Для этого достаточно щелкнуть мышью по верхнему краю окна. При этом внутри тега <grid> должны появиться следующие теги (цифры могут различаться): <Grid.ColumnDefinitions> <ColumnDefinition Width="134*" /> <ColumnDefinition Width="144*" /> </Grid.ColumnDefinitions>  Добавление списка. Перетащите на поверхность окна элемент управления ListBox (если список элементов управления не отображается, вам нужно щелкнуть мышью по поверхности окна). Растяните список так, чтобы он занимал весь левый столбец целиком. У вас должна получиться следующая разметка XAML:  <ListBox Grid.ColumnSpan="2" Margin="55,43,103,119" Name="listBox1" /> Добавьте в список элементы. Проще всего сделать это непосредственно редактируя разметку XAML. Замените созданный тег на набор тегов: <ListBox Name="listBox1" > <ListBoxItem> <Image Source="C:\WINDOWS\Blue Lace 16.bmp"></Image> </ListBoxItem> <ListBoxItem>Строка 1</ListBoxItem> <ListBoxItem>Строка 2</ListBoxItem> </ListBox> Примечание:в русифицированной версии Windows файл с рисунком называется Голубые Кружева 16.bmp Добавление обработчика события. Выполните двойной щелчок по списку для того, чтобы добавить обработчик события SelectionChanged. При этом Visual Studio автоматически переключится на редактор исходного кода C#. Обработчик должен выполнять следующий код: private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e) { MessageBox.Show(string.Format("Вы выбрали {0}пункт в списке", listBox1.SelectedIndex)); } Запуск приложения. Нажмите F5 для запуска приложения. Попробуйте изменить размер окна. Что при этом происходит со списком? Щелкните по рисунку в списке. Что произошло? Рисование фигур. Фигуры представляют собой один из основных элементов WPF. С их помощью можно рисовать двумерную графику, используя прямоугольники, линии, многоугольники и ломанные линии. Все эти фигуры представлены соответствующими классами, унаследованными от абстрактного класса Shape, определенными в пространстве имен System.Windows.Shapes. Рассмотрим пример применения XAML, в котором рисуется рожица с ножками, состоящая из лица в виде окружности, двух эллипсов, изображающих глаз, кривой линии рта и четырех отрезков прямых линий, изображающих ноги. <Window x:Class="WpfApplication2.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Wpf Sample" Height="300" Width="300"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="42*" /> <RowDefinition Height="220*" /> </Grid.RowDefinitions> <Button HorizontalAlignment="Left" Margin="38,9,0,10" Name="button1" Width="75"> Button </Button> <Button HorizontalAlignment="Right" Margin="0,10,44,8" Name="button2" Width="75"> Button </Button> <Canvas> <Ellipse Canvas.Left="50" Canvas.Top="50" Width="100" Height="100" Stroke="Blue" StrokeThickness="4" Fill="Yellow" /> <Ellipse Canvas.Left="60" Canvas.Top="65" Width="25" Height="25" Stroke="Blue" StrokeThickness="3" Fill="White" /> <Ellipse Canvas.Left="70" Canvas.Top="75" Width="5" Height="5" Stroke="Blue" StrokeThickness="3" Fill="White" /> <Path Name="Mouth" Stroke="Blue" StrokeThickness="4" Data="M 62, 125 Q 95,122 102, 108"/> <Line X1="124" X2="132" Y1="144" Y2="166" Stroke="Blue" StrokeThickness="4" /> <Line X1="114" X2="133" Y1="169" Y2="166" Stroke="Blue" StrokeThickness="4" /> <Line X1="92" X2="82" Y1="146" Y2="168" Stroke="Blue" StrokeThickness="4" /> <Line X1="68" X2="83" Y1="160" Y2="168" Stroke="Blue" StrokeThickness="4" /> </Canvas> </Grid> </Window> В процессе формирования каждой строчки кода обращайте внимание на то, что происходит с изображением лица в дизайнере формы. После завершения формирования кода XAML можно увидеть конечный результат, представленный на рис.1.  Рис.1. Внешний вид дизайнера формы. Поскольку все изображение основано на векторах, то его можно легко масштабировать. В следующем фрагменте кода демонстрируется выполнение такого преобразования, увеличивающее рисунок в полтора раза: <Canvas.LayoutTransform> <ScaleTransform ScaleX="1.5" ScaleY="1.5" /> </Canvas.LayoutTransform> 1.5. Особенности использования технологии WPF. 1.5.1. Еще раз о технологии WPF. Класс отделенного кода XAML позволяет конструировать пользовательский интерфейс, но для того, чтобы создать функционирующее приложение, нужен способ подключения обработчиков событий, содержащих код вашего приложения. XAML позволяет легко это сделать с помощью атрибута Class, показанного ниже: <Window x:Class="WindowsAppiication1.Window1" Префикс пространства имен х помещает атрибут Class в пространство имен XAML, что означает более общую часть языка XAML. Фактически атрибут Class сообщает анализатору XAML, чтобы он сгенерировал новый класс с указанным именем. Этот класс наследуется от класса, именованного элементом XML. Другими словами, в этом примере создается новый класс по имени Window1, который наследуется от базового класса Window. Класс Window1 генерируется автоматически во время компиляции. И здесь начинается самое интересное. Вы можете предоставить часть класса Window1, которая будет объединена с автоматически сгенерированной частью этого класса. Специфицированная вами часть — блестящий контейнер для вашего кода обработки событий. На заметку! Это волшебство возможно благодаря средству С#, известному под названием частичных классов. Частичные классы позволяют разделить класс на две или более отдельных части во время разработки, которые соединяются вместе в компилированной сборке. Частичные классы могут быть использованы во многих сценариях управления кодом, но более всего удобны, когда ваш код должен объединяться с файлом, сгенерированным дизайнером. Среда Visual Studio помогает вам за счет автоматического создания частичного класса, куда вы можете поместить свой код обработки событий. Например, если вы создаете приложение по имени WindowsApplication, содержащее окно по имени Windowl (как и в предыдущем примере), то Visual Studio начнет с создания следующего базового каркаса класса: namespace windowsApplication1 { /// <summary> /// interaction logic for Windowl.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent (); } } } Когда вы компилируете ваше приложение, то текст на языке XAML, определяющий ваш пользовательский интерфейс (такой как Window1.xaml) транслируется в объявление типа CLR, объединенного с логикой вашего файла класса отделенного кода (подобного Window1.xaml.cs), формируя один общий модуль. 1.5.2. Метод InitializeComponent () В данный момент класс Window1 не содержит никакой реальной функциональности. Однако он включает одну важную деталь — конструктор по умолчанию, который вызывает InitializeComponent (), когда вы создаете экземпляр класса. На заметку! InitializeComponent () играет ключевую роль в приложениях WPF. По этой причине вы никогда не должны удалять вызов InitializeComponent() из конструктора вашего окна. Аналогично, если вы добавите другой конструктор, предусмотрите в нем вызов InitializeComponent(). Метод InitializeComponent () не видим в вашем исходном коде, потому что генерируется автоматически при компиляции вашего приложения. По существу все, что делает InitializeComponent() — это вызов метода LoadComponent() класса System.Windows.Application. Метод LoadComponent() извлекает код BAML (компилированный текст на языке XAML) из вашей сборки и использует его для построения вашего пользовательского интерфейса. При разборе BAML он создает объекты каждого элемента управления, устанавливает их свойства и прикрепляет все обработчики событий. На заметку! Если вам не терпится, загляните в конец главы. Там, в разделе "Код и компилированный XAML" вы найдете код автоматически сгенерированного метода InitializeComponent (). Именование элементов. Есть еще одна деталь, которую следует принимать во внимание. В классе отделенного кода вам часто захочется программно манипулировать элементами управления. Например, вы можете читать либо изменять свойства, прикреплять или откреплять обработчики событий на лету. Чтобы обеспечить такую возможность, элемент управления должен включать XAML-атрибут Name. В предыдущем примере элемент Grid не включает атрибут Name, поэтому вы не сможете манипулировать им в отделенном коде. Вот как можно присвоить имя элементу Grid: <Grid x:Name = "grid1"> </Grid> Вы можете провести это изменение в документе XAML вручную, или же выбрать элемент в дизайнере Visual Studio и установить свойство Name в окне Properties (Свойства). В обоих случаях атрибут Name сообщит анализатору XAML-текста о необходимости добавить поле следующего вида к автоматически сгенерированной части класса Windowl: private System.Windows.Controls.Grid grid1; Теперь вы можете взаимодействовать со своим элементом в коде вашего класса Window1, используя имя grid1: MessageBox.Show(String.Format("The grid is {0}x{l} units in size.", grid1.ActualWidth, grid1.ActualHeight)); Такая техника мало, что дает простому примеру, но становится намного важнее, когда вам нужно читать значения из вводных элементов управления, таких как текстовые поля и списки. Свойство Name, показанное ранее, является частью языка XAML и используется для того, чтобы помочь в интеграции вашего класса отделенного кода. Некоторая путаница происходит из-за того, что многие классы определяют свое собственное свойство Name. (Примером может служить базовый класс FrameworkElement, от которого наследуются все элементы WPF.) Анализаторы XAML элегантно справляются с этой проблемой. Вы можете либо установить XAML-свойство Name (используя префикс х:), либо свойство Name, относящееся к действительному элементу (пропустив префикс). В любом случае результат один и тот же — специфицированное вами имя используется в файле автоматически сгенерированного кода и применяется для установки свойства Name. Это значит, что следующая разметка эквивалентна тому, что вы уже видели: <Grid Name="grid1"> </Grid> Этот трюк работает только в том случае, если включающий свойство Name класс оснащен атрибутом RuntimeNameProperty. Этот атрибут указывает на то, какое свойство должно трактоваться как имя экземпляра этого типа. (Очевидно, обычно таким свойством является Name.) Класс FrameworkElement включает атрибут RuntimeNameProperty, так что никаких проблем нет. Совет. В традиционном приложении Windows Forms каждый элемент управления имеет имя. В приложении WPF такого требования нет. Однако если вы создаете окно перетаскиванием элементов на поверхность дизайна Visual Studio, то каждому элементу присваивается автоматически сгенерированное имя. Таково соглашение. Если вы не собираетесь взаимодействовать с элементом в вашем коде, то можете удалить атрибут Name из кода разметки. В примерах, предлагаемых в настоящей книге, имена элементов обычно пропускаются, если они не нужны, что сокращает код разметки. Теперь у вас должно появиться базовое понимание того, как интерпретировать документ XAML, определяющий окно, и как документ XAML преобразуется в конечный компилированный класс (с добавлением любого написанного вами кода). В следующем разделе мы рассмотрим синтаксис свойств более подробно, и узнаем, как привязывать к элементам обработчики событий. Свойства и события в XAML До сих пор мы рассматривали окно, содержащее пустой элемент управления Grid. Теперь рассмотрим более сложное окно автоответчика, включающее несколько элементов управления. Оно включает четыре элемента управления: Grid (чаще всего используемая для организации компоновки в WPF), два объекта TextBox и один Button.  Разметка, которая необходима для компоновки и конфигурирования этих элементов управления, существенно длиннее, чем в предыдущих примерах. Рассмотрим сокращенный листинг, в котором скроем некоторые детали и заменим их многоточиями для того, чтобы продемонстрировать только общую структуру. <Window x:Class="EightBall.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Eight Ball Answer" Height="300" Width="300"> <Grid Name="Grid1"> <Grid.Background> </Grid.Background> <Grid.RowDefinitions> </Grid.RowDefinitions> <TextBox Name="txtQuestion" ... > </TextBox> <Button Name="cmdAnswerH . .. > </Button> <TextBox Name="txtAnswer" ... > </TextBox> </Grid> </Window> На заметку! XAML не ограничены классами, входящими в WPF. Можно использовать XAML для создания экземпляра любого класса, который подчиняется нескольким основным правилам. |