Элемент управления Menu

87

ASP.NET предлагает еще один многофункциональный элемент управления, поддерживающий иерархические данные - Menu. Подобно TreeView, элемент управления Menu можно связать с источником данных или заполнить его вручную (декларативно или программно) с помощью объектов MenuItem.

Класс MenuItem не является таким же многофункциональным, как TreeNode - например, объекты MenuItem не поддерживают флажки или программную установку развернутого/свернутого состояния. Тем не менее, у них есть много похожих свойств, среди которых свойства, отвечающие за настройку изображений, определяющие, можно ли выбирать элемент, а также свойства, определяющие целевую ссылку. Стандартные свойства MenuItem описаны в таблице ниже:

Свойства MenuItem
Свойство Описание
Text

Текст, отображаемый в меню для данного элемента (при его отображении)

ToolTip

Текст контекстной подсказки, которая появляется при наведении указателя мыши на элемент меню

Value

Хранит неотображаемое значение с дополнительными данными об элементе меню (например, уникальный идентификатор, используемый при обработке событий щелчка для идентификации узла или поиска дополнительной информации)

NavigateUrl

Если это значение установлено, то при щелчке на данном узле он автоматически направляет пользователя по указанному URL-адресу. В противном случае придется повторно среагировать на событие Menu.MenuItemClick, чтобы решить, какое действие нужно выполнить

Target

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

Selectable

Если это свойство будет иметь значение false, то элемент нельзя будет выбрать. Обычно значение false присваивается этому свойству только тогда, когда элемент является подзаголовком, содержащим выбираемые дочерние элементы

ImageUrl

Если это свойство установлено, оно будет определять изображение, отображаемое рядом с элементом меню (справа от текста). По умолчанию изображение не используется

PopOutImageUrl

Изображение, которое отображается рядом с элементом меню (справа от него), если этот элемент имеет вложенные элементы меню. По умолчанию этим изображением является маленькая сплошная стрелка

SeparatorImageUrl

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

По структуре элемента управления Menu можно перемещаться точно так же, как и по структуре TreeView. Элемент управления Menu содержит коллекцию объектов MenuItem в свойстве Items, а каждый объект MenuItem имеет коллекцию ChildItems с вложенными элементами. Например, пример из предыдущей статьи, в котором элемент управления TreeView служил для отображения списка категорий и товаров, можно было адаптировать, просто изменив имена нескольких классов. Ниже приведен необходимый код:

protected void Page_Load(object sender, EventArgs e)
{
        if (!Page.IsPostBack)
        {
            // Извлечь DataSet с помощью вспомогательного метода
            DataSet ds = GetProductsAndCategories();

            // Циклический проход по записям категорий
            foreach (DataRow row in ds.Tables["Categories"].Rows)
            {
                // Создать пункт меню для категории
                MenuItem itemCategory = new MenuItem(
                    row["CategoryName"].ToString(),
                    row["CategoryID"].ToString());

                Menu1.Items.Add(itemCategory);

                // Получить дочерние элементы (товары) для данного
                // родительского элемента (категории)
                DataRow[] childRows = row.GetChildRows(ds.Relations[0]);

                // Циклический проход no всем товарам данной категории
                foreach (DataRow childRow in childRows)
                {
                    MenuItem itemProduct = new MenuItem(
                        childRow["ProductName"].ToString(),
                        childRow["ProductID"].ToString());

                    itemCategory.ChildItems.Add(itemProduct);
                }
            }
        }
}

private DataSet GetProductsAndCategories()
{
        // Реализация кода доступа к базе данных 
        // аналогична примеру для TreeView
}

protected void Menu1_MenuItemClick(object sender, MenuEventArgs e)
{
        if (Menu1.SelectedItem.Depth == 0)
            Label1.Text = "Вы выбрали категорию с CategoryID: ";
        else
            Label1.Text = "Вы выбрали товар с ProductID: ";

        Label1.Text += "" + Menu1.SelectedItem.Value + "";
 }

Результат выполнения этого кода показан на рисунке ниже:

Отображение меню с информацией из базы данных

В общем случае элементы управления Menu и TreeView демонстрируют поразительно похожие модели программирования, даже несмотря на то, что они генерируются по-разному. Кроме того, они имеют подобную модель форматирования, основанную на стилях. И все же между ними есть несколько существенных отличий:

Стили элемента управления Menu

Элемент управления Menu предлагает огромное количество стилей. Подобно TreeView, Menu предлагает два класса, производных от базового класса Style: MenuStyle и MenuItemStyle. Эти стили делают доступными свойства интервалов (ItemSpacing, HorizontalPadding и VerticalPadding). Однако посредством стиля нельзя задавать изображения элемента меню, поскольку у него нет свойства ImageUrl.

Подобно TreeView, элемент управления Menu поддерживает определение стилей меню для различных уровней меню. Однако главная отличительная особенность, свидетельствующая в пользу элемента управления Menu, связана со статическими элементами (элементами корневого уровня, которые отображаются на странице при первой ее генерации) и динамическими элементами (элементами в плавающих меню, которые добавляются при наведении указателя мыши на часть меню). На большинстве веб-сайтов существует четкое различие в применении стилей к этим двум элементам. Для этого в классе меню определены два параллельных набора стилей: один применяется к статическим элементам, а другой - к динамическим, как показано в таблице ниже:

Стили элемента управления Menu
Статический стиль Динамический стиль Описание
StaticMenuStyle DynamicMenuStyle

Определяет внешний вид всего "окна", в котором появляются все элементы меню. В случае StaticMenuStyle это "окно" отображается на странице, а в случае DynamicMenuStyle - как всплывающее "окно"

StaticMenuItemStyle DynamicMenuItemStyle

Определяет внешний вид отдельных элементов меню

StaticSelectedStyle DynamicSelectedStyle

Определяет внешний вид выбранного элемента. Имейте в виду, что выбранным является не тот элемент, на который наведен указатель, а тот элемент, который был выбран до этого щелчком мыши (и который инициировал последнюю обратную отправку)

StaticHoverStyle DynamicHoverStyle

Определяет внешний вид элемента, на который пользователь навел указатель мыши

С помощью описанных наборов можно устанавливать стили, специфичные для уровней, чтобы разнообразить внешний вид каждого уровня меню и подменю. Это можно сделать с помощью трех коллекций: LevelMenuItemStyles, LevelSubMenuStyles, LevelSelectedStyles. Данные коллекции применяются к обычным меню, к меню, содержащим другие пункты, а также к выбранным пунктам меню, соответственно.

Разделение динамических и статических стилей здесь может показаться излишним. Доводы в пользу этой модели станут очевидными, если рассмотреть другую примечательную особенность элемента управления Menu - он позволяет выбирать количество статических уровней. По умолчанию существует только один статический уровень, а все остальное отображается в виде плавающего меню, когда пользователь наводит указатель мыши на соответствующий родительский элемент. Однако с помощью свойства Menu.StaticDisplayLevels картину можно изменить. Например, если установить Menu.StaticDisplayLevels в 2, то первые два уровня меню будут генерироваться на странице с использованием статических стилей.

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

<asp:Menu ID="Menu1" runat="server" BackColor="#B5C7DE" DynamicHorizontalOffset="2" 
	Font-Names="Verdana" Font-Size="0.8em" ForeColor="#284E98" StaticSubMenuIndent="10px"
	OnMenuItemClick="Menu1_MenuItemClick" StaticDisplayLevels="2">
	<DynamicHoverStyle BackColor="#284E98" ForeColor="White" />
	<DynamicMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" />
	<DynamicMenuStyle BackColor="#B5C7DE" />
	<DynamicSelectedStyle BackColor="#507CD1" />
	<StaticHoverStyle BackColor="#284E98" ForeColor="White" />
	<StaticMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" />
	<StaticSelectedStyle BackColor="#507CD1" />
	<LevelMenuItemStyles>
	    <asp:MenuItemStyle BackColor="Blue" Font-Bold="True" Font-Underline="False" ForeColor="White" />
	</LevelMenuItemStyles>
</asp:Menu>
Меню с двумя статическими уровнями

Элемент управления Menu предлагает еще очень много высокоуровневых свойств для настройки специфических аспектов визуализации. Например, можно установить задержку до исчезновения всплывающего меню (DisappearAfter), определить, какие будут использоваться изображения по умолчанию для значков развертывания и разделителей, задать поведение при прокрутке (которое проявляется, когда окно браузера оказывается слишком маленьким, чтобы уместить в себе всплывающее меню) и многое другое. Полный список свойств можно найти в справочной системе Visual Studio.

Шаблоны элемента управления Menu

Посредством свойств StaticMenuItemTemplate и DynamicMenuItemTemplate элемент управления Menu поддерживает также и шаблоны. Эти шаблоны определяют HTML-код, который будет генерироваться для каждого элемента меню, предоставляя вам полный контроль.

Интересно отметить, что шаблон можно использовать независимо от того, как заполняется класс Menu - декларативно или программно. С точки зрения шаблона всегда осуществляется привязка к объекту MenuItem. Это значит, что шаблон всегда должен извлекать значение для элемента из свойства MenuItem.Text, как показано в следующем примере:

<asp:Menu ID="Menu1" runat="server">
	<StaticItemTemplate>
		<%# Eval("Text") %>
	</StaticItemTemplate>
</asp:Menu>

Одна из целей использования средств шаблонов Menu состоит в том, чтобы показать множество фрагментов информации, полученной из объекта данных. Например, может понадобиться отобразить заголовок и описание, полученные из SiteMapNode для данного элемента (а не просто заголовок). К сожалению, сделать это невозможно. Дело в том, что объект Menu связан непосредственно с объектом MenuItem. Объект MenuItem предоставляет свойство DataItem, но на момент добавления его в меню это свойство больше не будет иметь ссылки на SiteMapNode, которая использовалась для его заполнения. В результате, практически ничего нельзя сделать.

Пройди тесты
Лучший чат для C# программистов