Методология синхронной разработки приложения в Microsoft Visual Studio 2010

Размещение элементов управления

Показывать лекцию целиком

Цель лабораторной работы: показать способы размещения элементов управления (Canvas, StackPanel, Grid). Рассмотрим каждый из этих элементов, чтобы получить о них более полное представление. Закрепить знания, полученные в лекции 1.

Задания для самостоятельного выполнения

Разместить на экране Grid с двумя колонками и двумя строками. Нижнюю строку объединить и положить в неё StackPanel. В StackPanel разместить несколько элементов управления. Задать им расположение по вертикали, выравнивание по центру.

Учебный элемент. Создание нового проекта для Silverlight в VisualStudio 2010

Silverlight и WPF имеют общие корни и используют одинаковый подход к созданию приложений при помощи XAML. В данном учебном элементе максимально просто и понятно будут рассмотрены основные особенности при программировании на Silverlight. По традиции в качестве примера будет использован стандартный проект "Здравствуй, мир!".

Проект будет разрабатываться на Visual Studio 2010, но в данном случае это не принципиально. Поэтому, если вы еще не перешли на новую версию среды разработки, то можете использовать и VS2008.

Шаг 1. Создание проекта

Запустим Visual Studio и посмотрим, как создавать новые проекты для Silverlight (р. 2.1).

(рис 2.1) Создание нового проекта Silverlight

Если вы раньше выбирали подгруппу Windows для разработки стандартных приложений, то теперь вам нужно выбирать подгруппу Silverlight, в которой находятся несколько типов шаблонов: Silverlight Application, Silverlight Class Library и Silverlight Navigation Application.

Для нашего первого примера возьмем шаблон Silverlight Navigation Application и присвоим своему проекту имя SilverlightHelloWorld.

В следующем окне (р. 2.2) Вам нужно выбрать тип проекта.

(рис 2.2) Выброр типа проекта Silverlight

Используем настройки по умолчанию, и выбираем ASP.NET Web Application Project. В этом случае Вам будет проще отлаживать код и не придется использовать различные веб-сервисы.

Итак, Вы присвоили имя новому проекту и выбрали его тип. Откроется заготовка для проекта в среде разработки (р. 2.3). Для начала изучим структуру стандартного проекта, которую можно видеть в правой части экрана:

(рис 2.3) Структура проекта Silverlight

Вы можете видеть множество различных файлов, которые были созданы без нашего участия. Рассмотрим их.

Итак, наибольший интерес для нас представляют следующие файлы:

  • App.xaml – очень важный для приложения, в котором описаны ресурсы и различные глобальные события. Также в этом файле содержится точка входа в программу. А также содержатся инструкции для плагина Silverlight.
  • MainPage.xaml – это страница, которая является частью выбранного вами шаблона. По умолчанию, страница имеет имя MainPage, но вы можете выбрать свое имя при желании. При помощи кода в этом файле мы можем настроить интерфейс будущей программы.
  • Папки Assets/Views – в папках содержатся вспомогательные файлы: картинки, стили и т.п.
  • XAML-файлы позволяют визуализировать интерфейс программы. Файлы XAML основаны на XML и имеют свой язык разметки, который мы будем менять в этом учебном элементе.

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

    Для просмотра приложения используются две тестовые страницы для ASP.NET, и HTML. Содержание страниц одинаково, поэтому один из этих файлов Вы можете безболезнено удалить. Если удалите тестовую страницу для ASP.NET, то нужно сделать оставшуюся тестовую страницу SilverlightHelloWorldTestPage.html стартовой (через контекстное меню выберите команду Set As Start Page).

    Шаг 2. Добавляем элементы интерфейса для XAML-страниц

    В нашем шаблоне, который мы выбрали для примера, имеются некоторые возможности для навигации (это видно по названию шаблона). В папке Views имеются файлы About.xaml, ErrorWindow.xaml и Home.xaml. Сосредоточимся на файле Home.xaml, который первым выводится на экран при запуске. Откройте файл двойным щелчком и Вы увидите код, который хранится в файле.

    Рассматривая XAML-код, можно увидеть, что содержимое страницы содержится в контейнере Grid, например, такие стандартные элементы, как StackPanel и TextBlock. Элемент TextBlock предназначен для вывода текста и является аналогом элемента Label, знакомого Вам по WinForm. Запустите приложение (F5), не внося никаких изменений, чтобы увидеть, что из себя представляет программа. Вы увидите следующее окно:

    (рис 2.4) Стартовая страницы созданного Silverlight приложения

    Обратите внимание на кнопки-ссылки в верхнем правом углу. Они отвечают за навигацию. Давайте теперь добавим свой код, чтобы понять, как работать с XAML.

    Предположим, мы хотим добавить кнопку. В файле Home.xaml, который у Вас открыт, напишите после второго TextBlock следующее:

    <Button Content="Click me" 
        x:Name="MyButton" FontSize="18" Width="150" Height="45" />

    Вы уже заметили, что XAML-редактор состоит из двух частей. И когда вы пишете код, то в окне Design в интерактивном режиме сразу появляются описываемые элементы управления. После того, как Вы напечатали указанный код, Вы увидите кнопку с заданными параметрами после текста Home page content. Обратите внимание на атрибут x:Name. Это уникальный идентификатор для элемента и, именно, по этим идентификаторам мы сможем обращаться к элементам из фонового кода. Любая уважающая себя кнопка позволяет пользователю щелкать по ней мышью. Вот как это делается в XAML. Достаточно при описании кнопки добавить атрибут Click, далее VS Intellisense услужливо спросит Вас, хотите ли сгенерировать обработчик для события:

    (рис 2.5) Intellisense

    Впрочем, Вы можете по старинке написать код для обработчика события вручную не в самом XAML, а в файле Home.xaml.cs:

    public Home()
    {
        InitializeComponent();
        MyButton.Click += new RoutedEventHandler(MyButton_Click);
    }

    Когда мы определили функцию MyButton_Click, то можем написать управляемый код в функции. Для первого примера давайте поменяем текст в элементе TextBlock под именем HeaderText (HeaderText является значением атрибута x:Name и мы можем обратиться к нему через это имя). Щелкнем дважды на созданной кнопке, чтобы сразу оказаться в нужном месте кода в редакторе и напишем следующее:

    void MyButton_Click(object sender, RoutedEventArgs e)
    {
        HeaderText.Text = "Hello World!";
    }

    Если теперь запустить приложение снова, то увидим нашу кнопку. Щелкнув по ней, мы изменим текст:

    (рис 2.6) Результат работы функции MyButton_Click

    Учебный элемент. Silverlight: размещение элементов

    В первом учебном элементе мы рассмотрели базовые приемы программирования. Теперь разберем вопрос размещения элементов в Silverlight-приложениях. Размещение элементов на форме в Windows Forms было простым занятием. Мы просто перетаскивали нужный элемент с панели инструментов на форму и задавали ему нужные свойства. В приложениях, основанных на XAML, используется другой подход. Важно разобраться с основными принципами размещения элементов в XAML, так как это является основой для дальнейшего успешного программирования на Silverlight (и WPF).

    Шаг 1. Принципы разметки

    Silverlight использует гибкую систему для размещения видимых элементов управления на поверхности. Разметка в коде поддерживает два стиля размещения: динамический и абсолютный. Основными элементами, которые помогают размещать элементы являются:

  • Canvas
  • StackPanel
  • Grid
  • Рассмотрим каждый из этих элементов, чтобы получить о них более полное представление. Для демонстрации воспользуемся привычными нам кнопками, которые будет размещать на поверхности нашего приложения. Вы можете заново создать новый проект или продолжить работу над предыдущим примером. Будем вносить изменения в коде файла Home.xaml.

    Canvas

    Элемент Canvas является одним из базовых элементов разметки и позволяет размещать элементы привычным нам способом при помощи задания нужных координат (именно такой способ мы использовали в Windows Forms. Например, попробуем разместить три кнопки следующим образом:

    <Canvas>
    <Button Canvas.Top="50" Canvas.Left="50" Content="Button 1" FontSize="18" 
            Width="150" Height="45" />
    
    <Button Canvas.Top="150" Canvas.Left="20" Content="Button 2" FontSize="18" 
            Width="150" Height="45" />
    
    <Button Canvas.Top="70" Canvas.Left="80" Canvas.ZIndex="99"
            Content="Button 3" FontSize="18" Width="150" Height="45" />
    </Canvas>

    На экране мы увидим следующую картинку:

    (рис 2.7) Результат размещения контролов на элементе разметки Convas

    Как Вы видите, мы просто задаем координаты для кнопок. В случае необходимости мы также можем указать порядок ZIndex, если одна кнопка перекрывает другую. Подобная модель размещения элементов вполне годится при создании игр или демонстрации каких-то физических процессов. Также Canvas подойдет в тех случаях, когда элементы статичны и хорошо смотрятся в различных ситуациях. Но, на самом деле, существуют более удобные контейнеры, которые вытесняют Canvas, и избавляют программиста от множества проблем, возникаемых при разработке удобных приложений. К числу таких элементов относятся StackPanel или Grid.

    StackPanel

    StackPanel - элемент-контейнер, который размещает элементы в ряд по вертикали или горизонтали (по умолчанию используется вертикальное размещение). Вот как можно расположить три кнопки по вертикали:

    <StackPanel>
        <Button Margin="10" Content="Button 1" FontSize="18"
                Width="150" Height="45" />
        <Button Margin="10" Content="Button 2" FontSize="18" 
                Width="150" Height="45" />
        <Button Margin="10" Content="Button 3" FontSize="18"
                Width="150" Height="45" />
    </StackPanel>
    (рис 2.8) Результат размещения контролов на элементе разметки StackPanel

    Веб-разработчик может увидеть здесь некоторое сходство с блоковыми элементами HTML (например, DIV), которые размещаются с новой строки. Если Вы хотите разместить кнопки по горизонтали, то достаточно присвоить атрибуту Orientation элемента StackPanel значение Horizontal:

    <StackPanel Orientation="Horizontal">
        <Button Margin="10" Content="Button 1" FontSize="18"
                Width="150" Height="45" />
        <Button Margin="10" Content="Button 2" FontSize="18"
                Width="150" Height="45" />
        <Button Margin="10" Content="Button 3" FontSize="18"
                Width="150" Height="45" />
    </StackPanel>
    (рис 2.9) Orientation элемента StackPanel в значении Horizontal

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

    Grid

    Grid (сетка) используется очень часто. Возвращаясь к сравнению с элементами HTML, можно сказать, что данный контейнер похож на элемент TABLE (таблица), так как тоже использует столбцы и ряды. Небольшое отличие состоит в том, что в XAML мы сначала задаем структуру для Grid, а уже потом начинаем описывать элементы, которые будут находиться в сетке. Очень удобно, что у Grid есть атрибут ShowGridLines, который показывает линии сетки, что позволит нам наглядно увидеть пример с расположением кнопок (в реальных примерах вы можете не выводить сетку).

    <Grid ShowGridLines="True">
      <Grid.RowDefinitions>
          <RowDefinition Height="60" />
    	<RowDefinition Height="60" />
    	<RowDefinition Height="60" />
      </Grid.RowDefinitions>
    
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="175" />
        <ColumnDefinition Width="175" />
        <ColumnDefinition Width="175" />
    </Grid.ColumnDefinitions>
    
    <Button Grid.Column="0" Grid.Row="0" Content="Button 1" FontSize="18" 
            Width="150" Height="45" />
    <Button Grid.Column="2" Grid.Row="0" Margin="10" Content="Button 2" 
            FontSize="18" Width="150" Height="45" />
    <Button Grid.Column="1" Grid.Row="2" Margin="10" Content="Button 3" 
            FontSize="18" Width="150" Height="45" />
    </Grid>

    Если внимательно изучить код, то видим, что мы определили три колонки и три ряда и указали их размеры. Далее мы размещаем кнопки, указывая их положение при помощи Grid.Column и Grid.Row:

    (рис 2.10) Результат размещения контролов на элементе разметки Grid

    В Expression Blend размещать элементы удобнее, так как в нем реализован удобный редактор размещения. Поэтому Вам стоит изучить данную программу и использовать ее в своих разработках.

    Шаг 2. Создаем Twitter-приложение

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

    (рис 2.11) Вот как выглядит наше будущее приложение в эскизе

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

    Мы поступили дальновидно, выбрав шаблон с навигацией. Внесем некоторые изменения в файле MainPage.xaml. Около строки 29 удалим логотип приложения (<ContentControl Style="{StaticResource LogoIcon}"/>), а также изменим текст для ApplicationnameTextBlock на Twitter Search Monitor.

    Оставим на минутку наш проект и займемся его структурой. В окне Solution Explorer найдите папку Views, и при помощи контекстного меню создайте новую страницу под именем Search.xaml. Для этого щелкните правой кнопкой на папке Views, далее выберите команды Add | New Item... и в следующем диалоговом окне выберите шаблон Silverlight Page:

    (рис 2.12) Выбор шаблона Silverlight Page

    У нас появится пустая XAML-страница с сеточной разметкой Grid (по умолчанию). На этой странице мы создадим окно поиска, эскиз которого был показан выше.

    Шаг 3. Навигация

    Изучим основные особенности навигации, используемой в нашем шаблоне. Мы видим, что шаблон состоит из файла MainPage.xaml и дополнительных элементов Home, About. Навигация состоит из трех важных состаляющих: UriMapper, Frame и Page.

    UriMapper

    В двух словах сложно объяснить, что такое UriMapper. Считайте, что это удобный способ сокращения ссылок. Например, вместо использования строки /Views/Home.xaml, вы можете настроить приложение таким образом, что ссылка будет выглядеть как /Home. Разработчики PHP могут найти тут сходство с настройкой файла .htaccess. UriMapper является частью элемента Frame в MainPage.xaml:

    <navigation:Frame x:Name="ContentFrame"
                      Style="{StaticResource ContentFrameStyle}" 
                      Source="/Home" Navigated="ContentFrame_Navigated" 
                      NavigationFailed="ContentFrame_NavigationFailed">
      <navigation:Frame.UriMapper>
        <uriMapper:UriMapper>
            <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>
            <uriMapper:UriMapping Uri="/{pageName}" 
                       MappedUri="/Views/{pageName}.xaml"/>
        </uriMapper:UriMapper>
      </navigation:Frame.UriMapper>
    </navigation:Frame>

    Frame

    Frame - это область для навигации. Вы сначала настраиваете эту область по умолчанию, а затем она меняется при навигации. Если посмотреть на код, приведенный выше, то увидите, что значением атрибута Source для элемента Frame является /Home.

    Page

    И, наконец, последний важный элемент навигации - это элемент Page, который мы создали сами. Данный элемент является контейнером для содержимого, который выводится в Frame. Можете рассматривать его как элемент UserControl, который вы можете добавлять в проект.

    Шаг 4. Размещаем элементы для страницы поиска

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

    Поместим на страницу Grid с двумя рядами: первый ряд для поисковой строки и кнопки, а второй ряд для вывода результатов. В верхнем ряду расположим элемент StackPanel и добавим на него текстовое поле и кнопку. Чтобы элементы располагались друг за другом, присвоим у StackPanel значение Orientation=Horizontal.

    Далее добавим элемент DataGrid, предназначенный для работы с данными, во второй ряд сетки. Код для страницы будет выглядеть следующем образом:

    <navigation:Page x:Class="SilverlightHelloWorld.Views.Search" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:d=http://schemas.microsoft.com/expression/blend/2008
        xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
        mc:Ignorable="d"
        xmlns:navigation="clr-namespace:System.Windows.Controls;
                              assembly=System.Windows.Controls.Navigation"
        d:DesignWidth="640" d:DesignHeight="480"
        Title="Twitter Search Page" 
        xmlns:data="clr-namespace:System.Windows.Controls;
                              assembly=System.Windows.Controls.Data">
     <Grid x:Name="LayoutRoot">
      <Grid.RowDefinitions>
        <RowDefinition Height="32"/>
        <RowDefinition/>
      </Grid.RowDefinitions>
      <StackPanel HorizontalAlignment="Left" Margin="0,-32,0,0" 
                  VerticalAlignment="Top" Grid.Row="1" Orientation="Horizontal">
        <TextBox x:Name="SearchTerm" FontSize="14.667" Margin="0,0,10,0"
                 Width="275" TextWrapping="Wrap"/>
        <Button x:Name="SearchButton" Width="75" Content="SEARCH"/>
      </StackPanel>
      <data:DataGrid x:Name="SearchResults" Margin="0,8,0,0" Grid.Row="1" />
     </Grid>
    </navigation:Page>

    Обратите внимание на запись xmlns:data в начале кода. Так можно добавлять свои элементы управления в XAML, после добавления ссылки на сборку. Сейчас приложение выглядит следующим образом (в Blend):

    (рис 2.13) Вид приложения в Blend

    Для идентификации мы дали имена x:Name для текстового поля (SearchTerm), кнопки (SearchButton) и DataGrid (SearchResults). Можно приступать к написанию кода.

    Шаг 5. Изменяем UriMapper для Search.xaml

    Мы практически закончили работать над интерфейсом страницы поиска. Так как она является лицом нашего приложения, то неплохо бы сделать ее главной. Внесем некоторые изменения в файле MainPage.xaml. Найдите в нем Frame и поменяйте в нем строчку таким образом, чтобы по умолчанию открывалась наша поисковая страница, а не Home.xaml:

    <navigation:Frame x:Name="ContentFrame" 
                      Style="{StaticResource ContentFrameStyle}" 
                      Source="/Search" Navigated="ContentFrame_Navigated" 
                      NavigationFailed="ContentFrame_NavigationFailed">
        <navigation:Frame.UriMapper>
            <uriMapper:UriMapper>
                <uriMapper:UriMapping Uri="" MappedUri="/Views/Search.xaml"/>
                <uriMapper:UriMapping Uri="/{pageName}" 
                           MappedUri="/Views/{pageName}.xaml"/>
            </uriMapper:UriMapper>
        </navigation:Frame.UriMapper>
    </navigation:Frame>

    Нам больше не нужен файл Home.xaml, поэтому смело удаляем его из проекта. Далее добавим новый файл History.xaml и изменим в MainPage.xaml область LinksBorder, чтобы включить ссылку на него:

    <Border x:Name="LinksBorder" Style="{StaticResource LinksBorderStyle}">
      <StackPanel x:Name="LinksStackPanel" Style="{StaticResource 
                    LinksStackPanelStyle}">
    
        <HyperlinkButton x:Name="Link1" Style="{StaticResource LinkStyle}" 
             NavigateUri="/Search" TargetName="ContentFrame" Content="home"/>
    
        <Rectangle x:Name="Divider1" Style="{StaticResource DividerStyle}"/>
    
        <HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}" 
             NavigateUri="/History" TargetName="ContentFrame" Content="history"/>
    
        <Rectangle x:Name="Divider2" Style="{StaticResource DividerStyle}"/>
    
        <HyperlinkButton x:Name="Link3" Style="{StaticResource LinkStyle}" 
             NavigateUri="/About" TargetName="ContentFrame" Content="about"/>
    
      </StackPanel>
    </Border>

    Сейчас программа выглядит следующим образом:

    (рис 2.14) Вид приложения в браузере

    Краткие итоги

    Мы создали первое приложение на Silverlight. Разобрали способы размещения элементов управления на таких панелях как Canvas, StackPanel и Grid. Познакомились с составляющими навигациии: UriMapper, Frame и Page.

    Вернуться к учебному плану