Контейнеры (Container, Panel, TabPanel, ViewPort) и разметки (BorderLayout, AccordionLayout, CardLayout)
Введение
Ну что же начнем. Нашей конечной целью будет создать интерфейс примерно похожий на Microsoft Outlook 2010. Почему именно этот интерфейс? Причина проста — потому что Ext.NET часто используется в корпоративном секторе или близком к нему и пользователь этой аудитории зачастую хочет видеть нечто похожее на Outlook. Плюс ко всему эта разметка довольно сложная и потому интересная. Не переживайте можно сделать и многие другие интерфейсы, но это все как-нибудь потом. Сразу оговорюсь, что мы не будем делать полную копию интерфейса Outlook, ограничимся только самым нужным.
Для начала создадим пустое ASP.NET приложение и назовем его "OutlookInterfaceWithExtNet".
Запустим «Package Manager Console (Tools -> Library Package Manager -> Package Manager Console)». И наберем следующую команду "PM -> Install-Package Ext.NET -Pre". С помощью NuGet импортируем Ext.NET и получим почти то же приложение, которое было в прошлом уроке
Подправим «Web.config», чтобы не добавлять везде ссылку на сборку с компонентами Ext.NET.
Удалим файл «Ext.NET.Default.aspx» из проекта, в этом проекте он нам не понадобится.
ViewPort, BorderLayout и AccordionLayout
Теперь когда все приготовления закончены, скопируем разметку из следующего примера http://examples.ext.net/#/ViewPort/Basic/Built_in_Markup/ в новый файл «Default.aspx». Удалим регистрацию сборки, она у нас и так прописана в Web.config. Получим следующую разметку:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Viewport with BorderLayout - Ext.NET Examples</title>
</head>
<body>
<ext:ResourceManager runat="server" />
<ext:Viewport runat="server" Layout="BorderLayout">
<Items>
<ext:Panel
runat="server"
Title="North"
Region="North"
Split="true"
Height="150"
BodyPadding="6"
Html="North"
Collapsible="true"
/>
<ext:Panel
runat="server"
Title="West"
Region="West"
Layout="AccordionLayout"
Width="225"
MinWidth="225"
MaxWidth="400"
Split="true"
Collapsible="true">
<Items>
<ext:Panel
runat="server"
Title="Navigation"
Border="false"
BodyPadding="6"
Icon="FolderGo"
Html="West"
/>
<ext:Panel
runat="server"
Title="Settings"
Border="false"
BodyPadding="6"
Icon="FolderWrench"
Html="Some settings in here"
/>
</Items>
</ext:Panel>
<ext:TabPanel runat="server" Region="Center">
<Items>
<ext:Panel
runat="server"
Title="Center"
Border="false"
BodyPadding="6"
Html="<h1>Viewport with BorderLayout</h1>"
/>
<ext:Panel
runat="server"
Title="Close Me"
Closable="true"
Border="false"
BodyPadding="6"
Html="Closeable Tab"
/>
</Items>
</ext:TabPanel>
<ext:Panel
runat="server"
Title="East"
Region="East"
Collapsible="true"
Split="true"
MinWidth="225"
Width="225"
Layout="Fit">
<Items>
<ext:TabPanel
runat="server"
ActiveTabIndex="1"
TabPosition="Bottom"
Border="false">
<Items>
<ext:Panel
runat="server"
Title="Tab 1"
Border="false"
BodyPadding="6"
Html="East Tab 1"
/>
<ext:Panel
runat="server"
Title="Tab 2"
Closable="true"
Border="false"
BodyPadding="6"
Html="East Tab 2"
/>
</Items>
</ext:TabPanel>
</Items>
</ext:Panel>
<ext:Panel
runat="server"
Title="South"
Region="South"
Split="true"
Collapsible="true"
Height="150"
BodyPadding="6"
Html="South"
/>
</Items>
</ext:Viewport>
</body>
</html>
Мы видим на этой странице следующее дерево разметки, в скобках указаны важные нам атрибуты:
- ViewPort
- Panel (Region = «North»)
- Panel (Layout=«AccordionLayout», Region=«West)
- Panel
- Panel
- TabPanel (Region=»Center")
- Panel (Title=«Center»)
- Panel (Title=«Close me»)
- Panel (Region=«East»)
- TabPanel (TabPosition=«Bottom»)
- Panel (Title=«Tab 1»)
- Panel (Title=«Tab 2»)
- TabPanel (TabPosition=«Bottom»)
- Panel (Region=«South»)
Прежде чем начать разбирать, давайте посмотрим, что отобразится в браузере. Сделаем эту страницу страницей по умолчанию и запустим. Мы увидим область, размеченную на 5 частей, причем она занимает всю область страницы.
Теперь давайте поймем, как же все так получилось. Начнем с самого главного узла – с ViewPort. В Ext.NET есть довольно много разнообразных контейнеров. Основная роль, которых размещать в себе некоторое количество других контролов. Все они наследуются от класса AbstractContainer и имеют специальную коллекцию Items, которая и содержит дочерние контролы.
В нашей разметке в корне дерева мы видим специальный контейнер, называется он "ViewPort", он имеет одно интересное, выделяющее его от остальных контейнеров свойство, он занимает всю доступную область на странице. Вы можете, как угодно изменить размер окна браузера и всегда ViewPort будет растягиваться вместе с ним, занимая все доступное пространство. Поэтому его удобно использовать как базовый элемент в разметке. Но у него есть одно ограничение, на странице может быть только один ViewPort, что само себе является логичным, ведь и окно браузера у вас только одно.
Теперь давайте обратим внимание на атрибут Layout у ViewPort, который имеет значение "border". Он имеет его неспроста и обычно они используются вместе. Давайте уберем этот атрибут и посмотрим, что получится.
В принципе ничего страшного не случилось, только Элементы внутри нашего ViewPort встали друг над другом. Типичное поведение для блочных элементов в HTML. Причина кроется в том, что атрибут Layout (Разметка) указывает способ расположение элементов в контейнере. Есть еще LayoutConfig, который выполняет тонкую настройку разметки. Эти свойства определены в базовом классе «AbstractContainer» и все контейнеры в Ext.NET наследуют это свойство.
Если вам интересно, какие еще бывают Layout'ы, то можете посмотреть на http://examples.ext.net в узле Layout. Сейчас мы будем обсуждать только те, что будут нам необходимы. Вы можете почитать неплохое руководство по разметке, правда, по ExtJS Pre, http://rawberg.com/wp-content/uploads/ExtJS-Layouts.pdf. В нем подробно изложены основные моменты работы с разметками, которые справедливы и для Ext.NET.
В нашем конкретном случае мы используем BorderLayout, он размещает дочерние элементы контейнера, в нашем случае это ViewPort, максимум на пять частей или минимум на одну. Чтобы понять по какому принципу он их размещает, давайте, обратим внимание на дочерние элементы ViewPort. Он содержит четыре Panel и один TabPanel и у каждого есть атрибут "Region", со значением из набора: "North ", «West», " Center ", " East ", " South". Как вы, наверное, уже догадались, они указывают на 4 стороны света и центральный элемент, т.е. на размещение этих элементов внутри контейнера ViewPort. Разметка "Border" имеет следующие правила:
- Всегда должен быть дочерний элемент с атрибутом Region=«Center».Поэтому должен быть как минимум один элемент в данной разметке
- Этот центральный элемент занимает место, которое осталось после выделения пространства всем остальным элементам, участвующим в разметке.
В принципе, ничего сложного в BorderLayout больше нет. Давайте подведем небольшой итог:
- В Ext.NET есть контейнеры, которые наследуются от AbstractContainer и содержат коллекцию дочерних элементов Items;
- Контейнеры, не влияют на расположение элементов, для этого используются свойства Layout и LayoutConfig;
- Есть специальный контейнер ViewPort, который занимает всю доступную область в окне браузера;
- Есть BorderLayout, который позволяет расположить в контейнере его дочерние элементы, с помощью атрибута Region.
Я так полагаю, что многие обратили внимание на панель со значением Region=«West» и заголовком «West», а вернее на значение ее атрибута Layout. Посмотрите на отображение ее дочерних элементов. Они сгруппированы в так называемую гармошку (accordion). Это сделано с помощью значения знакомого нам уже атрибута — Layout=«accordion». В принципе, в этом нет ничего сложного, поэтому на AccordionLayout мы задерживаться не будем.
Container, Panel, TabPanel
Контрол Panel является основным контейнером в Ext.NET.
Рассмотрим основные свойства класса Panel:
Название свойства | Тип | Унаследовано от | Описание |
AnimCollapse | bool | AbstractPanel | Указывает анимировать или нет сворачивание и разворачивание панели. Имеет смысл только, если свойство Collapsible равно true. |
BottomBar | Ext.Net.ToolbarCollection | AbstractPanel | Коллекция элементов, которые будут отображаться в самом низу панели |
Closable | bool | AbstractPanel | Можно ли закрыть панель |
CollapseMode | Ext.Net.CollapseMode | AbstractPanel | Определяет способ отображения кнопки сворачивания панели. Принимает одно из значений перечисления (Enum) CollapseMode: Default, Mini, Placeholder. Имеет смысл только, если свойство Collapsible равно true. По умолчанию 'Default'. |
Collapsible | bool | AbstractPanel | Указывает, может ли панель сворачиваться. По умолчанию 'false'. |
Defaults | Ext.Net.ParameterCollection | AbstractContainer | Набор параметров, которые будут добавлены к каждому элементу контейнера |
DefaultType | String | AbstractContainer | Указывает xtype для дочерних элементов по умолчанию. По умолчанию 'panel'. Xtype это уникальный идентификатор класса в ExtJS. Подробнее docs.sencha.com/ext-js/4-1/#!/api/Ext.AbstractComponent-cfg-xtype |
FooterBar | Ext.Net.ToolbarCollection | AbstractPanel | Коллекция элементов, которые будут отображаться в нижней части панели |
Items | Ext.Net.ItemsCollection<AbstractComponent> | AbstractContainer | Набор компонентов, которые будут отображаться внутри контейнера |
Layout | String | AbstractContainer | Указывает разметку элементов в контейнере |
LayoutConfig | Ext.Net.LayoutConfigCollection | AbstractContainer | Указывает параметры/настройки разметки элементов в контейнере |
LeftBar | Ext.Net.ToolbarCollection | AbstractPanel | Коллекция элементов, которые будут отображаться в левой части панели |
RightBar | Ext.Net.ToolbarCollection | AbstractPanel | Коллекция элементов, которые будут отображаться в правой части панели |
Title | String | AbstractPanel | Заголовок панели. По умолчанию '' |
Tools | Ext.Net.ToolsCollection | AbstractPanel | Набор кнопок, которые отображаются рядом с заголовком панели. Обычно используется для отображения кнопок помощь, свернуть, закрыть |
TopBar | Ext.Net.ToolbarCollection | AbstractPanel | Коллекция элементов, которые будут отображаться сверху панели |
Для ускорения отрисовки на стороне клиента вместо Panel можно использовать Container — более простую реализацию AbstractContainer. Давайте посмотрим, что будет, если в качестве дочерних элементов ViewPort, мы будем использовать Container, а не Panel. Код мы будем использовать следующий:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Viewport with BorderLayout - Ext.NET Examples</title>
</head>
<body>
<ext:ResourceManager ID="ResourceManager1" runat="server" />
<ext:Viewport ID="Viewport1" runat="server" Layout="BorderLayout">
<Items>
<ext:Container ID="Panel1"
runat="server"
Title="North"
Region="North"
Split="true"
Height="150"
BodyPadding="6"
Html="North"
Collapsible="true"
/>
<ext:Container ID="Panel2"
runat="server"
Title="West"
Region="West"
Layout="AccordionLayout"
Width="225"
MinWidth="225"
MaxWidth="400"
Split="true"
Collapsible="true">
<Items>
<ext:Panel ID="Panel3"
runat="server"
Title="Navigation"
Border="false"
BodyPadding="6"
Icon="FolderGo"
Html="West"
/>
<ext:Panel ID="Panel4"
runat="server"
Title="Settings"
Border="false"
BodyPadding="6"
Icon="FolderWrench"
Html="Some settings in here"
/>
</Items>
</ext:Container>
<ext:TabPanel ID="TabPanel1" runat="server" Region="Center">
<Items>
<ext:Container ID="Panel5"
runat="server"
Title="Center"
Border="false"
BodyPadding="6"
Html="<h1>Viewport with BorderLayout</h1>"
/>
<ext:Container ID="Panel6"
runat="server"
Title="Close Me"
Closable="true"
Border="false"
BodyPadding="6"
Html="Closeable Tab"
/>
</Items>
</ext:TabPanel>
<ext:Container ID="Panel7"
runat="server"
Title="East"
Region="East"
Collapsible="true"
Split="true"
MinWidth="225"
Width="225"
Layout="Fit">
<Items>
<ext:TabPanel ID="TabPanel2"
runat="server"
ActiveTabIndex="1"
TabPosition="Bottom"
Border="false">
<Items>
<ext:Container ID="Panel8"
runat="server"
Title="Tab 1"
Border="false"
BodyPadding="6"
Html="East Tab 1"
/>
<ext:Container ID="Panel9"
runat="server"
Title="Tab 2"
Closable="true"
Border="false"
BodyPadding="6"
Html="East Tab 2"
/>
</Items>
</ext:TabPanel>
</Items>
</ext:Container>
<ext:Container ID="Panel10"
runat="server"
Title="South"
Region="South"
Split="true"
Collapsible="true"
Height="150"
BodyPadding="6"
Html="South"
/>
</Items>
</ext:Viewport>
</body>
</html>
Размеры сохранились и содержимое элементов осталось. Чисто визуально мы потеряли только заголовки панелей, границу и фон стал прозрачным. Также потерялась небольшая кнопка, которая позволяла панели свернуться для увеличения места для центрального элемента, ее присутствие обеспечивалось значением следующего атрибута — Collapsible=«true». Но данный атрибут не поддерживается в Container и мы лишись этого функционала.
Давайте рассмотрим результаты профилировщика в обоих случаях – в случае использования Panel и в случае использования Container.
Результаты профилирования с использованием Container вместо Panel в ViewPort
Результаты профилирования с использованием Panel в ViewPort
Как видно из результатов, замена только 4 Panel на Container, уменьшило время на отрисовку более чем на 30мс (494 мс вместо 530мс) и количество вызовов функций JavaScript, на 7000(57236 вместо 64381). Что является довольно неплохим результатом, если учитывать, что обычно в Ext.NET приложениях используется несколько сотен Panel. Но если вы точно не уверены в выигрыше и преимуществах использования Container вместо Panel, я рекомендую использовать Panel. Зачастую это не приносит принципиального выигрыша в скорости, т.к. браузеры работают все быстрее, мощности клиентских машин тоже, а возможных проблем это может добавить в разы больше. Мы же не будем экономить и оставим Panel.
Следующий контейнер, который мы встречаем это "TabPanel" – панель для вкладок. Контрол является контейнером для Panel и каждый из них является вкладкой. Значение заголовка указывается в атрибуте "Title" контейнера, а если вы хотите, чтобы вкладку можно было закрыть, то обратите внимание на атрибут "Closable". TabPanel в своей реализации использует еще один интересный Layout — CardLayout. Подробно останавливаться на нем не будем. Вкратце, он представляет дочерние элементы контейнера как стопку карточек и отображает пользователю только верхнюю. Т.е. пользователю в каждый момент времени отображается только один элемент из его набора дочерних элементов. Чтобы понять, можете глянуть на следующий пример
Рассмотрим основные свойства класса TabPanel(т.к. TabPanel потомок AbstractPanel, то все свойства, описанные для Panel справедливы и для нее, но некоторые не будут работать т.к. не имеют смысла):
Название свойства | Тип | Унаследовано от | Описание |
ActiveTab |
Ext.Net.AbstractComponent | AbstractTabPanel | Идентификатор, индекс или непосредственно вкладка, которая будет отображаться по умолчанию. Полезно, если вам нужно, чтобы при отображении TabPanel была открыта, допустим 2, вкладка |
ActiveTabIndex | int | AbstractTabPanel | Индекс вкладки по умолчанию |
DeferredRender | bool | AbstractTabPanel | При значении True элементы вкладки не будут загружены в браузер до тех пор, пока вкладка не станет активной или видимой. Это позволяет ускорить производительность при большом количестве элементов во вкладках. При значении False элементы всех вкладок будут загружены сразу, зачастую понижает производительность. Используется в редких случаях: когда возникают проблемы с отображением контролов или когда пользователя раздражает задержка при нажатии на вкладку. По умолчанию True |
ItemCls | String | AbstractTabPanel | CSS класс который будет добавлен к каждой вкладке. По умолчанию «x-tabpanel-child» |
MaxTabWidth | int | AbstractTabPanel | Максимальная ширина вкладки |
MinTabWidth | int | AbstractTabPanel | Минимальная ширина вкладки |
TabAlign | Ext.Net.TabAlign | AbstractTabPanel | Направление вкладок. Либо справо налево(Ext.Net.TabAlign.Left), либо слева направо(Ext.Net.TabAlign.Left). По умолчанию Ext.Net.TabAlign.Left |
TabPosition | Ext.Net.TabPosition | AbstractTabPanel | Положение заголовков вкладок. Либо сверху(Ext.Net.TabPosition.Top), либо (Ext.Net.TabPosition.Bottom). По умолчанию Ext.Net.TabPosition.Top |
Создаем основную базовую разметку
Теперь имея полученный багаж знаний, мы можем приступить к созданию самой базовой разметки нашего приложения. В нем не будет очень многого, но ведь мы только начинаем. Все панели нашего ViewPort'а остались на месте, но в соответствии с нашими требованиями они получили должное оформление. Давайте посмотрим на разметку, которая получилась в итоге, вы можете ее вставить в Default.aspx и поработать с ней самостоятельно.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>«a la Outlook» приложение, часть 1</title>
</head>
<body>
<ext:ResourceManager ID="PageResourceManager" runat="server" />
<ext:Viewport ID="AppMainViewport" runat="server" Layout="BorderLayout">
<Items>
<ext:Panel ID="MenuPanel"
runat="server"
Title="Меню"
Region="North"
Height="100"
Html="Здесь будет меню"
Collapsible="true">
<Tools>
<ext:Tool Type="Help" runat="server"></ext:Tool>
</Tools>
</ext:Panel>
<ext:Panel ID="LeftSideNavPanel"
runat="server"
Title="Папки"
Region="West"
Layout="AccordionLayout"
Width="225"
MinWidth="225"
MaxWidth="400"
Split="true"
Collapsible="true"
CollapseMode="Placeholder">
<Items>
<ext:Panel ID="MailLeftSideNavPanel"
runat="server"
Title="Почта"
Border="false"
BodyPadding="6"
Icon="Email"
Html="Здесь будет список папок почты"
/>
<ext:Panel ID="CalendarLeftSideNavPanel"
runat="server"
Title="Календарь"
Border="false"
BodyPadding="6"
Icon="Calendar"
Html="Здесь будет календарь"
/>
<ext:Panel ID="ContactsLeftSideNavPanel"
runat="server"
Title="Контакты"
Border="false"
BodyPadding="6"
Icon="FolderUser"
Html="Здесь будут контакты"
/>
<ext:Panel ID="TasksLeftSideNavPanel"
runat="server"
Title="Задачи"
Border="false"
BodyPadding="6"
Icon="Tick"
Html="Здесь будут задачи"
/>
</Items>
</ext:Panel>
<ext:Panel ID="MainMailPanel" runat="server" Region="Center" Html="Здесь будет основная область для работы с почтой">
</ext:Panel>
<ext:Panel ID="TasksRightSidePanel"
runat="server"
Title="Встреч в будущем не намечено"
Region="East"
Collapsible="true"
CollapseMode="Placeholder"
Split="true"
MinWidth="225"
Width="225"
Html="Здесь будут отображаться текущие дела и встречи">
</ext:Panel>
<ext:Panel ID="AppMainStatusPanel"
runat="server"
Region="South">
<BottomBar>
<ext:StatusBar
ID="AppMainStatusBar"
runat="server"
DefaultText="Здесь будут отображаться статус приложения">
</ext:StatusBar>
</BottomBar>
</ext:Panel>
</Items>
</ext:Viewport>
</body>
</html>
И если мы это запустим, то получим следующий вид нашей главной страницы:
В разметке нет ничего сложного, это все знакомые нам компоненты. Однако если у вас возникают вопросы, то пишите.
На этом мы остановимся. Основа нашего приложения заложена, хотя она обычно одинаковая для всех приложений. В следующей части мы сделаем еще один шаг — сделаем верхнее меню (Ribbon) и попутно разберемся с Toobar, Button, SplitButton и прочими другими интересными компонентами.
Проект можете скачать тут
Спасибо за внимание и приятного чтения!
Автор: Baidaly