• Microsoft .NET
  • WPF и Silverlight
  • Элементы управления пользовательского интерфейса Silverlight (User Interface Controls)

Элементы управления пользовательского интерфейса Silverlight (User Interface Controls)

ОГЛАВЛЕНИЕ

Silverlight 2 обладает примерно тремя дюжинами элементов управления пользовательским интерфейсом (User Interface controls). Разработчики .NET уже знакомы с ASP.Net или (в частности) WPF и для них использование элементов управления Silverlight не будет сложной задачей.

Рис. 1-1. Элементы управления Silverlight (для удобства, построены в две колонки)

Элементы управления Silverlight были созданы для предоставления хорошего внешнего вида, расширяемой и настраиваемой функциональности. Более того, все стандартные элементы управления могут быть изменены во многих направлениях для удовлетворения ваших потребностей.

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

Данная статья рассматривает тему обработчиков событий. Стили (Styles), шаблоны (Templates) и специализированные элементы управления (Custom Controls) мы рассмотрим в следующих статьях.

Об области проектирования (Design Surface)

Текущая область проектирования (Design Surface) в Visual Studio доступна только для чтения (read only). То есть вы можете перетаскивать элементы управления на разметку (либо записать их вручную в файл Xaml), и вы сразу же увидите результат в области проектирования, но при этом вы пока не можете перетащить или совершать какие-либо манипуляции с элементами управления напрямую, в режиме редактирования. В данном случае альтернативой будет использование Expression Blend.

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

Элементы управления внешним видом (Layout Controls)

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

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

  1.   Grid - в частности, это таблица, используемая для позиционирования объектов по строкам и колонкам.
  2. StackPanel - используется для позиционирования объектов рядом друг с другом, либо друг над другом.
  3. Canvas - используется для абсолютного позиционирования (и не был изменени с Silverlight версии 1.0) 

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

Элемент управления Grid

Элементы управления Grid (не путайте с элементами управления DataGrid) предоставляют легкость в позиционировании при помощи табличной структуры. Вы объявляете строки и колонки и затем располагаете элементы управления в конкретную ячейку (в определенную колонку определенной строки).

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

В общем, вы объявляете табличную сетку, объявляете ее строки и колонки и затем начинаете позиционировать элементы управления в конкретные ячейки (т.е., первая колонка, 3 строка). Для того, чтобы увидеть все это в действии давайте создадим приложение Silverlight: Easy Grid.


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

Откройте Visual Studio 2008 и нажмите на "Создать проект" (Create Project) и затем в окне нового проекта вам понадобится создать проект C# используя шаблон приложения (Silverlight Application Template).

Выберите место расположения вашего приложения и назовите его по вашему желанию; удостоверьтесь в том, что вы обладаете новейшей структурой (framework).

Рис. 1-2. Создание нового проекта Silverlight

При нажатии на кнопку OK вас спросят о том, хотите ли вы создать веб-сайт (Web Site) , веб-приложение (Web Application) либо простую тестовую страницу, или же ы хотите привязать существующий веб-сайт; все это показано в следующем изображении.

Рис. 1-3. Выберите создание простой тестовой HTML страницы

Если вы создадите тест страницу, то проект будет достаточно простым, но если вы создадите проект веб-сайт (Web Site) или веб-приложение (Web Application), то тогда Visual Studio создаст два проекта для вас: приложение Silverlight и тестовое приложение - отличное решение для программирования с тестированием, но для нас это пока излишне.

Выберите вторую опцию (cоздание тестовой страницы), и пусть Visual Studio cоздаст простое приложение. Если Page.xaml не будет открыт автоматически - щелкните дважды по нему в Solution Explorer (Обозреватель решений). Вы увидите, что Visual Studio понял, что вам необходима табличная сетка в качестве вашего главного контейнера и создал один за вас, названный LayoutRoot. (Также обратите внимание на то, что UserControl является самым первым декларатором в каждом "page".

<UserControl x:Class="EasyGrid.Page"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Width="400" Height="300"> 

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

Определение Grid, созданное Visual Studio 2008, выглядит следующим образом:

<Grid x:Name="LayoutRoot" Background="White">
</Grid> 

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

Определяем строки (Rows) и свойства (Properties)

Вы определяете строки (Rows) для таблицы в пределах элемента Grid.RowDefinitions. Для каждого элемента Row вы добавляете элемент RowDefinition, который сам по себе может иметь различные свойства, включая определенную высоту, либо же вы можете установить такую высоту, которая будет пропорциональной доступной площади либо занимать все свободное пространство, не занятое другими строками.

<Grid x:Name="LayoutRoot" Background="White">
  <Grid.RowDefinitions>
    <RowDefinition Height="50" />
    <RowDefinition Height="30*" MaxHeight="70" />
    <RowDefinition Height="40*" MaxHeight="70" />
    <RowDefinition Height="*" MinHeight="30" MaxHeight="50" />
    <RowDefinition Height="Auto" MinHeight="5" MaxHeight="30" />
  </Grid.RowDefinitions>
</Grid>

Height="Auto"

C установкой Auto пространство Grid распределяется равномерно на основании размера, содержимого в строке.

Звезда или пропорциональное изменение размеров

При пропорциональном изменении размеров значение колонки или строки должно быть выражено Xaml в качестве *. 

<RowDefinition Height="*"

Тем не менее, вы можете присвоить одной колонке или строке в два раза больше пространства используя 2* (или отношение 5:7 используя 5* и 7*).

<RowDefinition Height="30*"
<RowDefinition Height="40*"

Если вы совместите это с минимальной (Minimum) или максимальной (Maximum) высотой (Height), то вы получите более изящный элемент управления:

<RowDefinition Height="30*" MaxHeight="70" />
<RowDefinition Height="40*" MaxHeight="70" />
<RowDefinition Height="*" MinHeight="30" MaxHeight="50" /> 

Минимальное и контролируемое пространство

По умолчанию, дочерние элементы табличной сетки занимают минимальное необходимое пространство для размещения максимального объема содержимого в пределах ячейки в определенной строке или колонке. Вы можете иметь более гибкий контроль над позиционированием используя свойства отступа (margin) и выравнивания (alignment) так, как это показано ниж.

Единицы измерения размера

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

  •   Auto - размер основан на свойствах размера объекта, помещенного в сетку
  • Pixel - размер в пикселях
  • Star - размер основан на пропорциях доступного пространства

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

Для того, чтобы увидеть эффект всего этого мы создадим пять строк, используя различные правила настройки размеров. Мы также создадим три колонки, не обладающие никакими правилами установки размера (!). Затем мы заполним нашу табличную сетку элементами управления и рассмотрим некоторые последствия. Вот тот код, который мы с вами разберем.

Пример 1-1. Xaml для EasyGrid

<UserControl x:Class="EasyGrid.Page"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Width="400" Height="300">
 
<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
      <RowDefinition Height="50" />
      <RowDefinition Height="30*" MaxHeight="70" />
      <RowDefinition Height="40*" MaxHeight="70" />
      <RowDefinition Height="*" MinHeight="30" MaxHeight="50" />
      <RowDefinition Height="Auto" MinHeight="5" MaxHeight="30" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>

<TextBlock x:Name="FirstNamePrompt "
     Grid.Row="0" Grid.Column="0" Text="First Name:" Margin="5"/>
   
<TextBox  x:Name="FirstName"
      Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"
      Width="150" Background="Bisque" Margin="5" />
          
    <TextBlock x:Name="LastNamePrompt "
     Grid.Row="1" Grid.Column="0" Text="First Name:" Margin="5"/>
   
<TextBox  x:Name="LastName"
      Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"
      Width="150" Background="Beige" Margin="5" />
     
   <TextBlock x:Name="SubscriberPrompt"
     Grid.Row="2" Grid.Column="0"  
     Text="Subscriber?" VerticalAlignment="Bottom" />
   
<CheckBox x:Name="PlanA" Grid.Row="2" Grid.Column="1"  
     Content="Plan A" IsChecked="true"
     VerticalAlignment="Bottom" />
   
<CheckBox x:Name="PlanB" Grid.Row="2" Grid.Column="2"  
     Content="Plan B" VerticalAlignment="Bottom" />
   
   <TextBlock x:Name="Hello" Text="Hello"
     Grid.Row="3" Grid.Column="2" VerticalAlignment="Bottom"/>
   
   <TextBlock x:Name="World" Text="World"
     Grid.Row="4" Grid.Column="2" VerticalAlignment="Bottom"
     FontFamily="Comic Sans MS" FontSize="24"
     FontWeight="Bold" Margin="0,20,0,0"/>
  </Grid>
</UserControl>

Результат обработки данного кода отображен ниже

Рис. 1-4. Обработанный код

Для начала важно понять, что код Xaml, продемонстрированный в Примере 1-1, включает все необходимое для создания элемента управления (является всем что необходимо) для того, чтобы создать элемент управления) Silverlight , показанного на изображении 1-4. Вы и вправду не увидите строки и колонки, но это с легкостью можно изменить. Найдите объявление элемента и установите его свойство ShowGridLines (Отображать линии сетки) в True (Intellisense поможет вам сделать это, как показано на Изображении 1-5)

Рис. 1-5. Добавление свойства ShowGridLines и установка его в значение True

Когда вы сделаете это, то вы увидите сетку; это может пригодиться во время разработки, но все же надо помнить о том, что надо вернуть значение в False до того, как вы начнете обработку приложения Silverlight!

Рис. 1-6. ShowGridLines делает выравнивание более видимым (Нажмите сюда для просмотра полноразмерного изображения.

Исследуем код Xaml

Первые строки создают элемент Grid и определяют способ разделения пространства между строками.

<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True" >
  <Grid.RowDefinitions>
    <RowDefinition Height="50" />
    <RowDefinition Height="30*" MaxHeight="70" />
    <RowDefinition Height="40*" MaxHeight="70" />
    <RowDefinition Height="*" MinHeight="30" MaxHeight="50" />
    <RowDefinition Height="Auto" MinHeight="5" MaxHeight="30" />
  </Grid.RowDefinitions> 

Как уже было описано выше, RowDefinitions определяет пять строк. Первая строка имеет фиксированную высоту, равную 50. Вторая и третья будут иметь размеры в пропорции 3:4 относительно друг друга, но каждая может быть не более 70. Следующая строка займет все оставшееся место, но никогда не будет менее 30 либо более 50. Последняя строка будет изменять свой размер относительно располагаемого в ней объекта, но при этом ограничена минимальным значением в 5 и максимальным в 30.

После указания определения колонок мы определим TextBlock и TextBox. Мы обсудим данные элементы управления более детально позже, но первый обычно используется в качестве ярлыка, а второй используется для пользовательского ввода.

<TextBlock
x:Name="FirstNamePrompt "
   Grid.Row="0"
Grid.Column="0"
   Text="First Name:"  
Margin="5"/> 

TextBlock имеет пять параметров. Они могут быть выровнены один над другим, либо выстроены в линию - как вам будет угодно. Первый параметр - это имя (FirstNamePrompt) и используется для предоставления возможности ссылки на объект в коде. Если вы дадите имя объекту в Xaml и сохраните в файле, данный объект доступен без необходимости объявления в ваших методах.

Поэтому, если вы сохраните данный файл, и вы спокойно можете написать

FirstNamePrompt.Text=”Hello”

из любого метода данного класса и тогда компилятор будет точно знать то, на что вы ссылаетесь!

Свойства Grid.Row и Grid.Column называются расширенными свойствами и на самом деле "позаимствованы" из табличной сетки для позиционирования TextBlock в пределах соответствующей ячейки.

Свойство Text делает как раз то, что вам необходимо и оно заполняет TextBlock текстом.

Мы позже несколько раз вернемся к свойству Margin (отступ). На данный момент я обращаю ваше внимание на то, что нам необходимы три формы:

  •   Единственное значение, которое задает отступ по всему пространству - то есть слева, справа, сверху и снизу
  • Два значения, где первое значение поровну разделено между левым и правым отступом, а второе разделено между верхним и нижним
  • Четыре значения, по порядку Left (левое), Top (верхнее), Right (правое), Bottom (нижнее).

За элементом TextBlock в первой колонке следует TextBox (ввод) во второй колонке. Свойства очень похожи, однако вам придется объявить ширину вашего TextBox и мы выберем фоновый цвет для TextBox.

Следующая пара схожа с первой.

Третья строка заполнена элементами TextBlock и двумя CheckBox. Обратите внимание на то, что они выровнены посредством свойств VerticalAlignment и на то, что свойство IsChecked первого CheckBox установлено в True, так что он будет отмечен при первом отображении страницы.

TextBlock четвертой строки отображает Hello и в последней строке TextBlock отображает World, но при этом имеет настроенные свойства FontFamily, FontSize и FontWeight.


StackPanel

Элементы управления StackPanel обычно скомбинированы с другими элементами управления внешним видом. Они позволяют выстраивать объекты друг над другом либо рядом друг с другом (как книги на полке).

Одним из удобств StackPanel является то, что вам не нужно предоставлять позицию объектов, содержащихся в StackPanel - они позиционированы относительно предыдущего объекта в Stack.

В следующем примере мы расположим TextBlock над TextBox, который в свою очередь будет находиться над элементом Button, а последний в свою очередь - над CheckBox:

<StackPanel Background="Beige" Orientation="Vertical" >
  <TextBlock Text="Your name?" 
     HorizontalAlignment="Left" Margin="10,2,0,1"/>
  <TextBox Width="150" Height="30"
     HorizontalAlignment="Left" Margin="10,2,0,1"/>
  <Button Content="Submit this information" 
     HorizontalAlignment="Left"
    Margin="10,2,0,1" Height="30" Width="150" />
  <CheckBox Content="With Zing!" HorizontalAlignment="Left"
     Margin="10,2,0,1" />
</StackPanel> 

В данном коде мы можем кое-что рассмотреть. Верхняя и нижняя линии отображают объявление StackPanel в файле Xaml. StackPanel объявлен с двумя атрибутами: цветом фона BackgroundColor (Beige) и Orientation (ориентацией) , которая может принимать значения Vertical или Horizontal.

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

Рис. 1-7. Документация, демонстрирующая членов Stack Panel

Установив свойство Orientation в Vertical, мы выстраиваем его содержимое друг над другом вместо построения в строку.

В пределах StackPanel объявлены четыре объекта и порядок их объявления определит порядок их выстраивания. У каждого свойство TextAlignment установлено в Left тем самым они будут выровненны, и у каждого будет установлено свойство Margin. Давайте более детально рассмотрим свойство Margin при помощи определения в документации:

public Thickness Margin { get; set; }

Свойство Margin на самом деле явялется объектом типа Thickness. Как уже отмечалось ранее, мы объявляем объект Thickness в Xaml одним из трех путей:

Во-первых, вы можете предоставить значение типа double, которое будет значением отступа со всех сторон (слева, сверху, справа и снизу) объекта. То есть, вы можете написать

<Button Content="Submit this information" 
 HorizontalAlignment="Left"
 Margin="100" Height="30" Width="150" /> 

Тем самым изолировав кнопку отступом в 100 со всех сторон,

Рис. 1-8. Отступы кнопки 

Обратите внимание на то, что для расположения кнопки на таком расстоянии надо учитывать размеры кнопки!

Вторым способом объявления Thickness (и в данном случае Margin) является предоставления суммы значений всех сторон (то есть, пары сторон - верхняя и нижняб левая и правая - будут иметь одинаковые размеры,

<Button Content="Submit this information" 
HorizontalAlignment="Left"
Margin="50,20" Height="30" Width="150" /> 

Результатом данного объявления является то, что левый и правый отступ равны 25, и верхний и нижний отступ равны 10.

Наконец, вы можете объявить каждую в отдельности, только необходимо помнить о последовательности:

Рис. 1-9. Отступы являются объектом Thickness

То есть - Left (левый), Top (верхний), Right (правый), Bottom (нижний); либо в данном случае, левый отступ равен 10, верхний отступ равен 2, правый - 0 и нижний - 1.

Как только четыре элемента управления расположены в Stack Panel и выровненны, StackPanel несет ответственность за их расположение,

Рис. 1-10. Stack Panel в действии 

Обратите внимание на то, что StackPanel ответственен за цвет своего фона и за выстраивание своего содержимого (четыре элемента управления) но каждый элемент ответственен за свое расположение и отступы.


Горизонтальные StackPanel

Если мы хотим передвинуть StackPanel для того, чтобы выровнять все элементы в строку, то нам необходимо сделать несколько дополнительных изменений. Не все элементы управления по умолчанию выстраиваются одинаковым способом (сверху, в центре и снизу) , поэтому мы явно установим их вертикальное выравнивание в "Center", точно также, как мы ранее установили их горизонтальное выравнивание в "Left". Давайте так же установим отступы для того, чтобы было небольшое пространство между каждым объектом.

<StackPanel Background="Beige" Orientation="Vertical" >
  <TextBlock Text="Your name?" 
    HorizontalAlignment="Left" Margin="10,2,0,1"/>
  <TextBox Width="150" Height="30"
    HorizontalAlignment="Left" Margin="10,2,0,1"/>
  <Button Content="Submit this information" 
     HorizontalAlignment="Left"
   Margin="10,2,0,1" Height="30" Width="150" />
  <CheckBox Content="With Zing!" HorizontalAlignment="Left"
     Margin="10,2,0,1" />
</StackPanel> 

Обратите внимание на то, что я устанавливаю левый отступ текстового поля в значение 5 (вместо 10) для того, чтобы он был ближе к TextBlock, служащий в качестве ярлыка.

Рис. 1-11. Stack Panel в горизонтальном положении


События элементов управления и их обработчики

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

Когда вы создаете управляемый код приложения Silverlight в Visual Studio, атрибут Class будет расположен автоматически, без вашего участия . Создайте новое приложение и назовите его EventHandler, и затем исследуйте первые пару строк, как это показано ниже,

<UserControl x:Class="EventHandler.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">

Объявление обработчиков событий

Существует два способа объявить обработчики событий в Silverlight: в файле Xaml или в фоновом коде. Если вы объявите обработчики событий в Xaml, то вы не сможете добавлять параметры. Обычным объявлением обработчика события в XAMl будут следующие строки

<Canvas Loaded="Canvas_Loaded">
  <Button x:Name="myButton" Content="Hello"
    Canvas.Left="10" Canvas.Top="10" />
</Canvas> 

Здесь я удалил элемент Grid, созданный Visual Studio, и объявил объект Canvas. Я также назначил обработчик события, названный "Canvas_Loader" к загружаемому (Load) событию (стандартному событию, вызываемому при запуске (создании) Canvas).

Затем я объявляю кнопку в Xaml и устанавливаю содержимое в Hello.

Данный код появляется в Page.xaml. В файле с фоновым кодом Page.xaml.cs я должен теперь реализовать обработчик события с именем, которое я обещал использовать,

private void Canvas_Loaded(object sender, RoutedEventArgs e)
{
 myButton.Content = "Please Click Me";

Первое, на что следует обратить внимание, это то, что метод является идентичным тому, который объявлен в Xaml. Во-вторых, этот метод следует шаблону всех обработчиков события .NET. Он совершает возврат (наподобие void) и получает два параметра: первый - вроде object (содержащий ссылку на объект,вызвавший собитие), и второй- вроде EventArgs или вроде унаследованного от EventArgs; в данном случае RoutedEventArgs. Мы скоро вернемся к RoutedEventArgs.

Реализация заключается в том, что при загрузке Canvas, он выхватывает кнопку, объявленную в файле Xaml, и изменяет его свойство Content с "Hello" на "Please, push me",

Рис. 1-12. Измененнное свойство содержимого

Даже в данном необычайно простом примере есть две важные вещи на которые необходимо обратить внимание:

  1.  Вам не надо было объявлять myButton в фоновом коде; оно было получено объявлением в Xaml.
  2. Кнопка изменила свои размеры для того, чтобы занять большую строку.

Объявление обработчиков событий в коде

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

В любом случае, если вы хотите объявить ваши обработчики событий правильно в коде, то с Visual Studio это очень просто. Самым обычным способом будет привязка обработчиков событий в обработчике событий OnLoaded, с этим событием (Loaded) привязанным в конструкторе страницы (Page).

Чтобы увидеть это все в действии вернемся к предыдущему коду и уберем обработчик события из Xaml. Добавьте СheckBox как это показано ниже,

<!-- <Canvas Loaded="Canvas_Loaded"> -->
<Canvas >
  <Button x:Name="theButton" Content="I'm Indented!"
    Canvas.Left="150" Canvas.Top="20" />
    
  <CheckBox x:Name="RushOrder" Content="Rush"
    Canvas.Left="50" Canvas.Top="20" FontSize="18" />
</Canvas> 

Заметьте, что оригинальный Canvas закомментирован и заменен элементом Canvas, который не имееет событий.

Сохраните файл Xaml и откройте фоновый класс.

В конструкторе напишите Lo. Выскочит Intellisense и предложит вам в помощь создать код для события Loaded, что вам как раз и нужно. Подсказка (рядом с окошком Intellisence) показывает тип события.

Рис. 1-13. Intellisense помогает в создании обработчика событий

Мы скоро вернемся к тому факту, что Loaded является RoutedEventHandler. Нажмите кнопку табуляции и выберите Loaded, напечатайте += для того, чтобы начать добавлять делегатов. Если делегаты и события являются новшеством для вас, то вы можете в любой книжке по .NET 3.5, C# или VB найти и прочитать различные источники по делегатам и событиям.

Intellisense проведет вас через все шаги привязывания к обработчику события и если вы ему позволите, то и создаст основу метода обработчика события, в конце расположив курсор в методе, который он заполнит исключением (в случае если вы забыли добавить значимую реализацию.)

public Page()
{
 InitializeComponent();
 Loaded += new RoutedEventHandler(Page_Loaded);  
}
 
void Page_Loaded(object sender, RoutedEventArgs e)
{
 throw new NotImplementedException();
}

Удалите исключение и зарегистрируйте обработчики событий из обычных событий для вашей кнопки (Сlick) и кнопки с независимой фиксацией CheckBox (Checked и Unchecked)

void Page_Loaded(object sender, RoutedEventArgs e)
{
     myButton.Click += new RoutedEventHandler(myButton_Click);
     RushOrder.Checked += new RoutedEventHandler(RushOrder_Changed);
     RushOrder.Unchecked += new RoutedEventHandler(RushOrder_Changed);

Будьте осторожны, Intellisense захочет назвать методы для Checked и Unchecked соответственно RushOrder_Checked и RushOrder_Unchecked, но нет никакой необходимости в двух методах. Мы перегрузим это путем написания имени, которое нам необходимо, RushOrder_Changed, которое заставит оба обработчика события использовать разделяемый обработчик события.

В разделяемом обработчике событий мы проверим статус IsChecked кнопки с независимой фиксацией и если она выбрана, то мы изменим текст в верхний регистр (просто для того, чтобы убедиться, что обработчик события работает).

void RushOrder_Changed(object sender, RoutedEventArgs e)
{
  if (RushOrder.IsChecked == true)
  {
  RushOrder.Content = "RUSH";
  }
  else
  {
  RushOrder.Content = "Rush";
  }

Заметка для программистов C#: мы должны писать

if (RushOrder.IsChecked == true)

а не

if (RushOrder.IsChecked)

потому, что IsChecked является новым логическим типом C# 3.0 ( bool?) , который подразумевает не два, а три возможных состояния: true, false или null.


Динамическое создание элементов управления

В Silverlight 2 все элементы управления Xaml являются изоморфными для объектов общеязыковой среды исполнения (CLR objects). То есть, все что вы можете создать в Xaml вы также можете создать в коде. 

Там , где вы можете написать

<Button x:Name="myButton" Content="Hello" />

вы также можете написать

Button myButton = new Button();
myButton.Content = "Hello";

Хотя вы можете создать все ваши элементы управления и объекты в коде, правила хорошего тона гласят о том, что лучше делать это в Xaml. Наиболее явной причиной будет то, что Xaml является очень "инструментарным" - то есть он несет в себе возможность модифицировать инструменты, как Visual Studio и Expression, и тем самым легче масштабировать, изменять и осуществлять поддержку.

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

Мы можем сделать минимальное изменение в нашей существующей программе и добавить другую кнопку по просьбе пользователя. Добавьте следующую кнопку к файлу Xaml (обратите внимание на то, что мы также называет полотно!)

<Canvas x:Name="myCanvas">
  <Button x:Name="myButton" Content="Hello"
      Canvas.Left="10" Canvas.Top="10"/>
  <Button x:Name="Another" Content="Add Another"
      Canvas.Left="10" Canvas.Top="50" />
  <CheckBox x:Name="rushOrder" Content="Rush"
      Canvas.Left="50" Canvas.Top="10" /> 

В результате будет добавлена кнопка на страницу, и она будет содержать в себе "Add Another". При нажатии на кнопку нам необходимо добавить другую кнопку к пользовательскому интерфейсу, при этом нам нужно обеспечить данную кнопку своими размерами, позицией и поведением.

Все это мы сделаем в фоновом коде.


Динамическое создание кнопки

Сохраните файл .xaml и откройте Page.xaml.cs

Первым делом вам надо добавить обработчик события для новой кнопки,

Another.Click += new RoutedEventHandler(Another_Click);

и добавить его реализацию, где вы создадите новую кнопку и установите ее свойства,

void Another_Click(object sender, RoutedEventArgs e)
{
  Button b = new Button();
  b.Content = "I live!";
  b.SetValue(Canvas.LeftProperty, 10.0);
  b.SetValue(
  Canvas.TopProperty,
  this.newButtonPosition);
  this.newButtonPosition += 30.0;
  b.Width = 100;
  b.Height = 20;
  b.Click +=new RoutedEventHandler(new_button_click);
  myCanvas.Children.Add(b);

Поскольку свойства Left и Top полотна на самом деле не являются свойствами кнопки Button (но являются расширенными свойствами), то вы настраиваете их при помощи метода SetValue, который получает два параметра. Первый является названием свойства, которое вы хотите настроить (Canvas.LeftProperty и Canvas.TopProperty) , что не так сложно найти поскольку Intellisense их вам предоставит, и второе значение (в нашем случае - типа double).

Поскольку я хочу иметь возможность нажимать на кнопку более одного раза, то мне не нужно иметь несколько кнопок, которые переписывают друг друга, и для этого мне нужна переменная экземпляра для слежки за наибольшим значением,
private double newButtonPosition = 100.0;

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

b.SetValue(
  Canvas.TopProperty,
  this.newButtonPosition);
this.newButtonPosition += 30.0; 

Вот что вы получите в результате

 

Рис. 1-14. Динамическое добавление кнопок

Относительно кнопки, которую мы добавляем, вам также необходимо обратить внимание на то, что мы добавляем регистрацию обработчика события,

b.Click +=new RoutedEventHandler(new_button_click);

Это означает, что для каждой добавленой кнопки (каждой из трех на изображении 1-8) регистрируется вызов new_button_click при ее нажатии. Вам понадобится записать данный обработчик события в ваш файл Page.xaml.cs,

void new_button_click(object sender, RoutedEventArgs e)
{
  Button btn = sender as Button;
  btn.Content = "Don't do that!";
  btn.IsEnabled = false;

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

Рис. 1-15. Отключаем динамические кнопки

Наконец-то! Ничего такого не произойдет, если вы не станете добавлять кнопки на страницу. В данном случае, вам нет необходимости добавлять их к LayoutRoot, так как их позиционирование осуществляется в пределах определенного холста (Canvas), и вы их можете добавить к нему

myCanvas.Children.Add(b);

При запуске программы они будут членами данного холста точно также, как если бы вы их добавили по отдельности в файл Xaml.

Скачать исходники примеров 

Источник