Управление внешним видом (Layout Management) в Silverlight 2

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

Разработчики, использующие Silverlight и WPF используют специальные панели (layout panel) для установки позиции и изменения размера элементов управления. Встроенные панели внешнего вида в Silverlight 2 включают в себя три наиболее используемые панели WPF:

  • Canvas
  • StackPanel
  • Grid

Контейнер Canvas

Контейнер Canvas очень прост и поддерживает позиционирование элементов управления в своих пределах при помощи явно заданных координат.

Вы позиционируете элементы в пределах контейнера Canvas при помощи свойства XAML "Attached Properties" (свойства крепления), которые позволяют вам указать позицию элемента относительно координат Left, Top, Right или Bottom  своего родительского элемента Canvas. Данные свойства позволяют родительской панели расширять набор свойств элемента управления, находящихся в его пределах. Canvas, указав свойство крепления для “Top” и ”Left”, в общем добавляет способность указывать левое и верхнее крепление у кнопки (Button) либо любого другого элемента пользовательского интерфейса, добавленного к Canvas - без какой-либо необходимости  добавления свойства к классу элемента или выполнения какого-либо изменения класса элемента.

Мы можем добавить две кнопки в контейнер Canvas и позиционировать их обеих в расстоянии 50 пикселей от левого края Canvas, а также 50 и 150 пикселей от верхнего края, при этом используя XAML, как это показано ниже (атрибуты Canvas.Left и Canvas.Top являются примерами синтаксиса свойства крепления):


Это обработает наши кнопки и вот как это будет выглядеть:


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

StackPanel

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

К примеру, мы можем использовать StackPanel для того, чтобы вертикально расставить три кнопки на нашей странице при помощи разметки XAML:

Во время рабочего цикла программы StackPanel автоматически расставит элементы управления Button в столбик за нас:

В качестве альтернативы мы можем установить свойство "Orientation" StackPanel в значение "Horizontal" вместо "Vertical" (которое установлено по умолчанию):


Это укажет StackPanel на то, что нужно выстроить элементы Button в ряд:


Контейнер Grid

Элемент управления Grid обладает наиболее гибкой функциональностью и поддерживает позиционирование элементов одновременно в несколько строк и столбцов. Концептуально он схож с HTML элементом Table.

В отличие от HTML Table вы не вставляете элементы в столбцы и строки. Вместо этого вы должны указать определения Row и Column элемента Grid при помощи свойств <Grid.RowDefinitions> и <Grid.ColumnDefinitions>, которые объявлены сразу же после элемента <Grid>. Затем вы можете использовать синтаксис XAML "Attached Property" по отношению к элементам содержащимся в пределах табличной сетки для того, чтобы указать строки и колонки, которые необходимо заполнить информацией.

К примеру, мы можем объявить, что Grid имеет три строки и четыре колонки, и затем позиционировать 4 кнопки в его пределах при помощи XAML:


Элемент Grid расположит элементы Button следующим образом:


В дополнение к поддержке абсолютного позиционирования (к примеру: Height="60") свойства RowDefinition and ColumnDefinition элемента также поддерживают режим автоматической установки размера (Height="Auto"), при котором ячейка табличной сетки изменяет размер в соответствии с ее содержимым (вы также можете указать максимальное и минимальное значения, что тоже может быть полезным).

Row и ColumnDefinitions элемента Grid также поддерживают такое свойство как "Proportional Sizing" (установка размеров по пропорциям), которая позволяет установить размер колонок и рядов сетки пропорционально относительно друг друга (к примеру, вы можете установить такую пропорцию, при которой вторая строка будет увеличиваться в 2 раза быстрее чем первая).

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

Использование панелей внешнего вида для составления нашей Digg-страницы

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


Для того, чтобы создать данную страницу мы должны сначала добавить корневую панель Grid , которая имеет в своих пределах два RowDefinitions.Первый элемент Row будет иметь высоту в 40 пикселей, а второму мы присвоим все оставшееся пространство (Height="*"):


Заметка: обратите внимание на то, что я установил свойство "ShowGridLines" в значение "True". Это позволит нам с легкостью визуализировать границы Row и Column в пределах элемента Grid когда мы будем тестировать во время рабочего цикла:


Затем мы  расположим второй контейнер Grid в качестве дочернего в пределах первой строки корневого контейнера Grid и будем использовать его для выстраивания верхней строки (шапки). Мы создадим три колонки в его пределах: одну - для заголовка (Title), вторую- для текстового поля поиска (Search TextBox), и третью - для кнопки поиска (Search Button):


Выполнив это мы получим основную расстановку элементов на нашей странице Digg:


Заметка: в качестве альтернативы к вложенным элементам Grid мы могли бы использовать один элемент Grid с тремя колонками и двумя строками, и также использовали бы свойства ColSpan/RowSpan элемента для объединения содержимого среди множества колонок (в точности как и таблицы в HTML). Я решил использовать вложенные элементы Grid поскольку мне кажется, что это будет легче понять читателю.

Теперь, после того как мы обустроили внешний вид нам нужно добавить элементы управления. 

Для строки заголовка мы будем использовать встроенный элемент <Border> (у которого свойство CornerRadius установлено в 10 для придания округлости) и добавим немного текста в него для того, чтобы у нас был заголовок (Title). Далее мы используем элемент <TextBox> во второй колонке для поисковой функции. Также мы вставим кнопку <Button> для поиска в третью колонку. Затем нам необходимо будет добавить указатель места заполнения для текста во второй строке, которую мы будем использовать для последующего отображения результата поиска.

Заметка: Далее я применяю информацию стилей (FontSize, Colors, Margins и т.д) напрямую к элементам управления. Позже, в данной статье я расскажу, как использовать Styles для получения и инкапсуляции данных настроек в отдельном файле (CSS) , который затем можно использовать в приложении. 


И теперь, при запуске нашего приложения мы увидим следующее:


Динамическое изменение размеров приложения

Вы могли уже заметить в XAML , указанном выше, что элемент управления верхнего уровня настроен так, что его ширина и высота заданы статически:


При таком положении дел наше приложение Silverlight всегда будет иметь один размер. Вы убедитесь в этом как только вы расширите окно браузера:


Ограничения встроенного приложения фиксированными границами в пределах HTML-страницы может быть пригодно в некоторых случаях, но нам скорее хотелось создать поисковое приложение Digg таким образом, чтобы оно имело динамические параметры размера в точности, как у HTML-страницы.

Хорошей новостью все же является то, что это не так сложно реализовать. Просто уберите атрибуты Width и Height из корневого элемента управления:


Наше приложение Silverlight автоматически расширит (или  уменьшит) размеры для того, чтобы правильно заполнить HTML контейнер. Поскольку файл SilverlightTestPage.html , в котором мы тестируем приложение, содержит наш элемент управления Silverlight в элементе HTML <div> с установленными в CSS шириной и высотой, то наше приложение Digg польностью заполнит окно обозревателя:


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


Когда мы уменьшаем окно обозревателя, текстовое поле поиска и кнопка не меняют своих размеров, поскольку колонки их контейнера Grid имеют заданую ширину. Элемент <Border> , содержащий наш заголовок "Digg Search", автоматически меняет размер, поскольку колонка контейнера, в котором он расположен, имеет параметр ширины, установленный как Width="*".

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

Следующие шаги

Теперь у нас готова основная структура нашего приложения Digg, а также определена строка заголовка.

Следующим шагом будет реализация функциональности поиска для нашего приложения - то есть получение запрашиваемой информации с сайта Digg.com при пользовательском запросе.

Источник