Показ дописів із міткою TabControl. Показати всі дописи
Показ дописів із міткою TabControl. Показати всі дописи

пʼятниця, 30 травня 2008 р.

Юзер контроли на ASP.Net

Сьогодні на роботі написав свій перший повноцінний юзер-контрол на ASP.Net - TabControl (вкладки). Наразі, щоправда, без AJAX - так сказало начальство :) На диво, в АСП версії 2.0 немає такого цінного і потрібного контрола, а значить його треба писати руцями.
Спочатку в двох словах опишу ідею, яку я нарив в гуглі: таб контрол пишеться за допомогою трьох стандартних контролів: Menu, MultiView i View. Перший буде виконувати роль кнопочок вверху вкладок, два інші - все, що внизу.
Почнемо з малого - опишемо клас TabView:
using System.Web.UI.WebControls;

namespace MyControlsLib.TabControl
{
public class TabView : View
{
public string TabName { get; set; }
}
}

Як бачимо, він всього лише розширює функціональність стандартного View, додаючи йому пропертю TabName - заголовок вкладки. Все =)
Тепер трохи складніше - опишемо клас TabMultiView, який і буде контейнером для наших TabView:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace MyControlsLib.TabControl
{
[ParseChildren(true, "Views")]
public class TabMultiView : CompositeControl
{
public TabMultiView()
{
m_MultiView = new MultiView();
m_Menu = new Menu();
}

protected override void CreateChildControls()
{
base.CreateChildControls();

m_Menu.MenuItemClick += Menu_Click;
int index = 0;
foreach (var tab in Views)
{
MenuItem item = new MenuItem(tab.TabName, index.ToString());
item.Selected = index == ActiveIndex;
m_Menu.Items.Add(item);

m_MultiView.Views.Add(tab);

index++;
}

m_Menu.Orientation = Orientation.Horizontal;

if(!string.IsNullOrEmpty(SelectedTabCssClass))
{
m_Menu.StaticSelectedStyle.CssClass = SelectedTabCssClass;
m_Menu.StaticSelectedStyle.HorizontalPadding = 0;
m_Menu.StaticSelectedStyle.VerticalPadding = 0;
}
else
{
m_Menu.StaticSelectedStyle.BackColor = Color.LightGray;
m_Menu.StaticSelectedStyle.ForeColor = Color.Black;
}

if(!string.IsNullOrEmpty(UnselectedTabCssClass))
{
m_Menu.StaticMenuItemStyle.CssClass = UnselectedTabCssClass;
m_Menu.StaticMenuItemStyle.HorizontalPadding = 0;
m_Menu.StaticMenuItemStyle.VerticalPadding = 0;
}
else
{
m_Menu.StaticMenuItemStyle.BackColor = Color.Black;
m_Menu.StaticMenuItemStyle.ForeColor = Color.White;
}

// multiview

Controls.Add(m_Menu);
Controls.Add(m_MultiView);
}

private void Menu_Click(object sender, MenuEventArgs e)
{
ActiveIndex = int.Parse(e.Item.Value);
}

protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if(ActiveIndex < 0)
{
if(Views.Count > 0)
{
throw new NotSupportedException("Invalid ActiveIndex property. You must set it correct.");
}
}
else
{
m_MultiView.Visible = true;
}
}

public string UnselectedTabCssClass { get; set; }
public string SelectedTabCssClass { get; set; }

public int ActiveIndex
{
get
{
object viewState = ViewState["ActiveIndex"];
if(viewState == null)
{
return -1;
}
return (int) viewState;
}
set
{
ViewState["ActiveIndex"] = value;
m_MultiView.ActiveViewIndex = value;
}
}

public List<TabView> Views
{
get
{
if (m_Tabs == null)
{
m_Tabs = new List<TabView>();
}
return m_Tabs;
}
}

private Menu m_Menu;
private MultiView m_MultiView;
private List<TabView> m_Tabs;
}
}


Тепер коротенько, що, де, коли і навіщо:
1. Наслідуємося від CompositeControl - це такий контрол, який дозволяє тримати всередині інші контроли - у нас же всередині будуть лежати TabView та менюшка.
2. Вписуємо в нього пропертю List<TabView> Views - отут якраз вони і будуть лежати. Вішаємо на клас атрибутик [ParseChildren(true, "Views")] - цим самим ми кажемо компілятору, що всі внутрішні контроли треба пхати в ліст "Views".
3. Пропертя int ActiveIndex - індекс активної вкладки. Значення тримаємо в ViewState - його потрібно зберігати між перезавантаженнями сторінки.
4. Перевантажуємо метод CreateChildControls() - в ньому потрібно створити контроли, з яких і буде складатися наш мега-контрол. Тут пробігаємося по Views - там уже сидять TabView, які ми вписали всередину контрола і витягуємо з них імена для елементів меню. Для кожного елемента потрібно запам'ятати в проперті Value його індекс - щоб знати, який TabView активувати при кліку на елементі. Крім того додаємо в m_MultiView таби. В кінці не забуваємо додати меню і мультів'ю в список контролів і обробити клік по пункту меню: m_Menu.MenuItemClick += Menu_Click;.
5. Додаємо купу фігні, яка відповідає за красивості з CSS-стилями.
Дописуємо в Web.config пару рядочків для зручності користування контролами:
<pages>
<controls>
<add assembly="MyControlsLib" namespace="MyControlsLib.TabControl" tagPrefix="my"/>
</controls>
</pages>

Все. Тепер можна користуватися:
<my:TabMultiView runat="server" ActiveIndex="0" SelectedTabCssClass="SelectedTab" UnselectedTabCssClass="UnselectedTab">
<my:TabView runat="server" TabName="Tab1">
<asp:Panel runat="server" CssClass="TabPanel">
Blah-Blah-Blah
</asp:Panel>
</my:TabView>
<my:TabView runat="server" TabName="Second tab">
<asp:Panel runat="server" CssClass="TabPanel">
Мне бы джина, я б тогда не путался в проводах<br />
Прям из Крыма по Днепру бы подтянул Карадаг<br />
До зарплаты за неделю не был бы на мели<br />
Королевы и принцессы in love with me, yeah.<br />
Тру бутылки, банки, кружки, баночки тоже тру<br />
Спрячу джина под подушку, достану поутру<br />
Вот тогда бы мы дел наделали, вот тогда б зажгли<br />
Все дела поотменять, потому что у меня...<br /><br />
На восьмом этаже - пати в неглиже<br />
На седьмом этаже - соседи спят уже<br />
На девятом этаже - медведи и Фаберже<br />
Этажом выше - спецназ на крыше.<br />

</asp:Panel>
</my:TabView>
<my:TabView runat="server" TabName="Yet another tab...">
<asp:Panel runat="server" CssClass="TabPanel">
Hello world!
</asp:Panel>
</my:TabView>
</my:TabMultiView>

Після легкої настройки CSS можна отримати таке:

Я думаю, будь-кому зрозуміло, що прикрашати контрол можна й далі - але це вже виходить за рамки цього меседжа.