Пользовательские элементы управления (User Controls) в Silverlight

ОГЛАВЛЕНИЕ

Пользовательские элементы управления являются основной единицей повторно используемого Xaml и прилагающегося к нему кода. Вы можете создавать пользовательские элементы управления различными способами. Два наиболее используемых способа – это создать новое приложение либо позволить Blend или Visual Studio создать их за вас. Возможно, это немного вас удивит, но если вы присмотритесь к Page.xaml и App.xaml,  то поймете, что они на самом деле являются пользовательскими элементами управления (UserControls).

Я создал приложение, названное KeyboardControl, и  в нем самыми первыми строками  Page.xaml являются:

<UserControl x:Class="KeyboardControl.Page"
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="600" Height="350">

Фоновый код выглядит следующим образом:

namespace KeyboardControl
{
    public partial class Page : UserControl
    {

Вы, скорее всего, уже создавали пользовательские элементы управления. Вторым способом создания пользовательских элементов управления является явное добавление его к вашему приложению. Щелкнув правой кнопкой мыши по проекту и выбрав Add®New Item, вы получите  диалоговое окно, которое предложит вам шаблон с пользовательским элементом управления Silverlight в качестве одной из опций.

Созданный пользовательский элемент управления (UserControl) является таким же, как Page.xaml, за исключением данного вами названия.

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

Наилучшим примером использования будет создание некоторой функциональности и присвоение ее некоторому пользовательскому элементу управления и затем повторное её  использование.

Создание повторно используемой функциональности

Повторное использование функциональности пригодно в том случае, если данная функциональность стоит того, чтобы ее еще раз использовали. Мы начнем c создания усовершенствованной формы. Вы можете вручную заполнить данную форму, но она также поддерживает клавишную комбинацию "быстрого вызова", в частности Ctrl-M добавляет адрес Microsoft, а Ctrl-C добавляет адрес музея компьютерной истории в Mountainview штата Калифорния.

 

Рисунок 4-1. Форма, заполненная посредством нажатия Control-C

Создание проекта Keyboard

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

  • Создание приложения
  • Добавления элементов управления и добавление обработчиков событий
  • Использование стилей

Поскольку настройка табличной сетки может оказаться утомительным занятием, я также включил стартовое приложение с исходным кодом (KeyboardStarter). Итак, запустите Visual Studio 2008 и создайте новое приложение, названное KeyboardControl

Далее демонстрируется блок текста с Home Address, а также все параметры табличной сетки, такие как граница и отступы. Подразумевается, что первым элементом управления будет StackPanel, поэтому мы можем с легкостью расположить элементы управления один над другим, а в пределах StackPanel у нас Grid.

<UserControl x:Class="KeyboardControl.Page"
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="500" Height="500">
    <StackPanel Background="White">
        <TextBlock Text="Home Address" FontFamily="Verdana" FontSize="24"
            HorizontalAlignment="Left" Margin="15,0,0,0"/>
    <Grid x:Name="AddressGrid" >
         <!--More Here-->
      </Grid>
    </Border>      
  </StackPanel>
</UserControl>

Установите цвет фона в какой-нибудь светлый цвет (к примеру Bisque). Также границу сетки можно сделать черной. Установите в сетке 7 строк и 5 колонок так, как это показано ниже,

<Border BorderBrush="Black"  BorderThickness="1" Margin="15">
<Grid x:Name="AddressGrid" Background="Bisque" >
    <Grid.RowDefinitions>
        <RowDefinition Height="10" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="auto" />
        <RowDefinition Height="10" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="10" />
        <ColumnDefinition Width="auto" />
        <ColumnDefinition Width="10" />
        <ColumnDefinition Width="auto"/>
        <ColumnDefinition Width="10" />
    </Grid.ColumnDefinitions>
    <!--More Here-->
</Grid>
</Border>

Устанавливаем стили для элементов управления

Табличная сетка будет заполнена четырьмя подсказками и четырьмя текстовыми полями ввода, но они все настроены вручную, и пока нас это устраивает. Вы можете просто скопировать приведенный ниже код в App.xaml в теги Application.Resources. Каждый Style определяет свой TargetType (т.е., Button или TextBlock) и затем устанавливает значение для каждого свойства, стилем которого оно хочет управлять. Мы создаем всего 2 стиля - один для TextBlocks, который будет использован в качестве ярлыков, и второй - для получения информации в TextBoxes.

Все TextBlocks будут выровнены по нижнему (Bottom) и левому (Left) краю, и у них будет установлен шрифт Verdana, размер шрифта 18, а текст будет синего цвета. Данные элементы TextBlock также будут иметь отступ в 5 пикселей со всех сторон

    <Application.Resources>
        <Style TargetType="TextBlock" x:Key="TextBlockPrompt">
            <Setter Property="VerticalAlignment" Value="Bottom" />
            <Setter Property="HorizontalAlignment" Value="Left" />
            <Setter Property="FontFamily" Value="Verdana" />
            <Setter Property="FontSize" Value="18" />
            <Setter Property="FontWeight" Value="Medium" />
            <Setter Property="Foreground" Value="Blue" />
            <Setter Property="Margin" Value="5" />
        </Style>

Все элементы TextBoxe будут иметь черный жирный шрифт Verdana размера 18, а также будут выровнены по нижнему левому краю. TextBox будет размером 250 на 30 и также будет иметь отступ в 5 пикселей со всех сторон.

        <Style TargetType="TextBox" x:Key="TextBoxStyle">
            <Setter Property="FontFamily" Value="Verdana" />
            <Setter Property="FontSize" Value="18" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Foreground" Value="Black" />
            <Setter Property="VerticalAlignment" Value="Bottom" />
            <Setter Property="HorizontalAlignment" Value="Left" />
            <Setter Property="Width" Value="250" />
            <Setter Property="Height" Value="30" />
            <Setter Property="Margin" Value="5" />
        </Style>
    </Application.Resources>

Создание элементов управления в элементе Grid

Вместо добавления информации о стиле TextBlock вручную , мы можем привязать информацию об атрибуте Style при помощи "key" для определения желаемого стиля. 

<TextBlock Text="Location: "
     Style="{StaticResource TextBlockPrompt}"
     Grid.Row="2" Grid.Column="1"  />

Это равноценно

<TextBlock Text="Location: "  
 VerticalAlignment="Bottom"
 HorizontalAlignment="Left"
 FontFamily="Verdana"
 FontSize="18"
 FontWeight="Medium"
 Foreground="Blue"
 Margin="5"
 Grid.Row="2" Grid.Column="1" />

Строка

Style="{StaticResource TextBlockPrompt}"

переходит в App.xaml и находит стиль, ключом которого является TextBlockPrompt и присваивает все значения разом. Точно так же мы можем присвоить все значения стиля TextBox привязанному текстовому полю.

<TextBox x:Name="Location"
    Style="{StaticResource TextBoxStyle}"
    Text ="Silverlight Central"
    Grid.Row="2" Grid.Column="3" />

Они сопоставимы и мы можем проделать то же самое с тремя другими элементами управления.

<TextBox x:Name="Address1"
    Style="{StaticResource TextBoxStyle}"
    Text="100 Main Street"
    Grid.Row="3" Grid.Column="3" />

<TextBlock Text="Address Line 2: "
    Style="{StaticResource TextBlockPrompt}"
    Grid.Row="4" Grid.Column="1"  />

<TextBox x:Name="Address2"
    Style="{StaticResource TextBoxStyle}"
    Text="Apartment 100"
    Grid.Row="4" Grid.Column="3" />

<TextBlock Text="City, State, Zip "
    Style="{StaticResource TextBlockPrompt}"
    Grid.Row="5" Grid.Column="1"/>
  
<TextBox x:Name="City"
    Style="{StaticResource TextBoxStyle}"
    Text="Boston, MA 01001"
    Grid.Row="5" Grid.Column="3"/>

Заметьте что Text для каждого из элементов управления TextBox жестко запрограммирован и отображается соответственно коду при запуске приложения,

Рисунок 4-2. Форма с явно заданными значениями

Будет уместно упомянуть что в данном случае приложение обладает ограниченными возможностями.

Двусторонняя привязка данных

Одним из мощных способов привязки данных, который поможет привязать данные об адресе, например из базы данных, XML-файла  или какого-либо другого хранилища данных, является использование бизнес-объекта в качестве посредника между хранилищем и пользовательским интерфейсом (приложением Silverlight). Давайте создадим объект для адреса,  сопоставимого с данными, которые мы хотим отобразить (несмотря на то, что обычный бизнес-объект ,скорее всего, не будет так тесно связан с конкретной страницей пользовательского интерфейса). Вместо того, чтобы утомлять вас кодом, я просто приведу вам свойства Properties и их переменные в следующей таблице:

Private Member Variable

Public Property

location

Location

address1

Address1

address2

Address2

city

City

Структура класса будет похожа на структуру используемую в уроке о привязке данных,

using System.Collections.Generic;
using System.ComponentModel;

namespace KeyboardControl
{
    public class Address : INotifyPropertyChanged
    {

Каждое свойство кроме своей переменной обладает своим методом для получения данных (Get) и методом установки данных (Set), которые также вызывают событие notification.

Как только вы заполните все общедоступные (public) свойства, вы сможете заменить все явно заданные значения Text Block привязанными значениями,

<TextBox x:Name="Location"
    Style="{StaticResource TextBoxStyle}"
    Text ="{Binding Location, Mode=TwoWay }"
    Grid.Row="2" Grid.Column="3" />

 
<TextBox x:Name="Address1"
    Style="{StaticResource TextBoxStyle}"
    Text ="{Binding Address1, Mode=TwoWay }"
    Grid.Row="3" Grid.Column="3" />

 
<TextBox x:Name="Address2"
    Style="{StaticResource TextBoxStyle}"
    Text ="{Binding Address2, Mode=TwoWay }"
    Grid.Row="4" Grid.Column="3" />

 
<TextBox x:Name="City"
    Style="{StaticResource TextBoxStyle}"
    Text ="{Binding City, Mode=TwoWay }"
    Grid.Row="5" Grid.Column="3"/>

Кое-что совсем отвлеченное

Давайте рассмотрим то, что мы имеем: форма, которая запрашивает информацию об адресе, а также объект Address, который может содержать либо предоставить данную информацию. Обратите внимание на то, что форма реализована согласно содержимому табличной сетки, названной "Address" содержащей  четыре элемента TextBlocks и четыре TextBoxes. Что бы мы хотели добавить к функциональности самой формы, так это реакция на "быстрые клавиши ". При нажатии Ctrl-M нам необходимо, чтобы форма была заполнена информацией о Microsoft, а нажатием  Ctrl-C  хотелось бы заполнить форму адресом музея компьютерной истории

 

Рисунок 4-3. Здание музея компьютерной истории