Pull to refresh

Урок 2. Создаем своё приложение на Ext.NET, часть 1

Reading time14 min
Views6.7K
Контейнеры (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»)


    • 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" имеет следующие правила:
  1. Всегда должен быть дочерний элемент с атрибутом Region=«Center».Поэтому должен быть как минимум один элемент в данной разметке
  2. Этот центральный элемент занимает место, которое осталось после выделения пространства всем остальным элементам, участвующим в разметке.

В принципе, ничего сложного в BorderLayout больше нет. Давайте подведем небольшой итог:
  1. В Ext.NET есть контейнеры, которые наследуются от AbstractContainer и содержат коллекцию дочерних элементов Items;
  2. Контейнеры, не влияют на расположение элементов, для этого используются свойства Layout и LayoutConfig;
  3. Есть специальный контейнер ViewPort, который занимает всю доступную область в окне браузера;
  4. Есть 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 и прочими другими интересными компонентами.
Проект можете скачать тут
Спасибо за внимание и приятного чтения!
Tags:
Hubs:
Total votes 11: ↑6 and ↓5+1
Comments10

Articles