Главная » Разработка для Windows Phone 7 » Механизм компоновки Windows Phone 7

0

Давайте проведем небольшой эксперимент. Перейдем к файлу XAML проекта TelephonicConversation и вставим в тег ScrollViewer следующий параметр:

HorizontalScrollBarVisibility="Visible"

И тут же произойдет разительное изменение. Все элементы TextBlock превратятся в длинные строки текста без переносов. Что случилось? Почему свойство элемента ScrollViewer имеет такое огромное влияние на элементы TextBlock?

Но такое поведение не должно вызывать удивления. Если у ScrollViewer есть горизонтальная полоса прокрутки, то должна быть и причина ее существования. Этой причины нет, если все слова всех TextBlock переносятся на новую строку в случае необходимости. Если же предполагается использование горизонтальной полосы прокрутки, текст параграфов должен быть выстроен в одну строку.

Однако было бы не лишним не только знать эту странность поведения, но понимать реальный механизм происходящего. Понимание системы компоновки – один из самых важных навыков создания приложений на Silverlight. Система компоновки – мощнейший механизм, но для непосвященных он может казаться довольно странным.

Создание компоновки в Silverlight – это двухпроходный процесс, начинающийся с вершины дерева визуальных элементов и проходящий вниз по всем потомкам элементов. В приложении для телефона на Silverlight он начинается с PhoneApplicationFrame, затем идет PhoneApplicationPage, после чего, скорее всего, Grid, и затем (обычно) StackPanel и второй Grid. В приложении TelephonicConversation процесс продолжается элементом ScrollViewer, который может включать собственный Border, затем StackPanel и, наконец, элементы

TextBlock. У этих элементов TextBlock нет дочерних элементов, поэтому на них цепочка заканчивается.

При первом проходе каждый элемент дерева опрашивает свои дочерние элементы для получения желаемого размера. При втором проходе элементы компонуют дочерние элементы на своей поверхности. Компоновка может быть простой или сложной. Например, у Border только один потомок, и для определения местоположения этого потомка относительно себя данному элементу необходимо учесть лишь толщину собственной рамки (BorderThickness). А вот компоновка дочерних элементов в производных от Panel классах – намного более сложная задача.

Когда родительский элемент запрашивает размер своих дочерних элементов, он, буквально, говорит: «Ты можешь быть такого размера. Насколько большим ты хочешь быть?» – и каждый дочерний элемент вычисляет для себя желаемый размер. Все размеры представляются в форме структуры Size со свойствами Width и Height. Если у дочернего элемента тоже есть потомки, он должен определять свой размер на основании их размеров. И этот процесс продолжается вниз по дереву элементов, вплоть до таких элементов, как TextBlock, у которых нет потомков.

Элементы определяют свой размер по-разному, в зависимости от природы элемента. Возьмем для примера TextBlock, который включает большой фрагмент текста, и свойству TextWrapping (Автоматический перенос текста на новую строку) которого задано значение Wrap (Выполнять перенос текста). В этом случае TextBlock проверяет значение свойства Width, чтобы выяснить, какой размер ему доступен и где должен выполняться разрыв строки. После этого он знает, сколько строк ему необходимо для отображения имеющегося текста, и какое пространство в вертикальном направлении требуется для размещения всех этих строк. Так TextBlock вычисляет желаемый размер.

Но тут есть одна сложность. Родительский элемент предоставляет своему потомку доступный размер посредством структуры Size, имеющей два свойства, Width и Height, типа double. Иногда свойству Width или Height (или обоим) родителя задано особое значение с плавающей точкой: Double.PositiveInfinity (Плюс бесконечность). В этом случае родитель, буквально, сообщает: «Потомок, я предлагаю в твое распоряжение неограниченное пространство по ширине [или по высоте, или в обоих направлениях]. Сколько тебе надо?»

Дочерний элемент не может ответить: «Я хочу все!». Несмотря на то, что дочерние элементы иногда пытаются занять весь предоставляемый размер, это запрещено. Запрашиваемый желаемый размер дочернего элемента должен быть конечным и неотрицательным.

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

Но в этом кроется парадокс: некоторые элементы, такие как TextBlock и Image, имеют неявно заданный подразумеваемый размер, который определяется размером форматированного текста или исходного растрового изображения. А у некоторых элементов, таких как Ellipse, такого подразумеваемого размера нет. Если Ellipse задан конкретный размер, он отображается такого размера. Но если Ellipse предлагается бесконечный размер, у него нет иного выбора, кроме как сжать себя полностью, до несуществования.

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

Источник: Чарльз Петзольд, Программируем Windows Phone 7, Microsoft Press, © 2011.

По теме:

  • Комментарии