Опубликован: 14.11.2006 | Доступ: свободный | Студентов: 5899 / 533 | Оценка: 4.18 / 3.74 | Длительность: 16:37:00
ISBN: 978-5-9556-0085-7
Лекция 11:

Навигация по сайту

< Лекция 10 || Лекция 11: 12345 || Лекция 12 >

Программное управление TreeView

У TreeView есть множество событий. Событие SelectedNodeChanged запускается, когда пользователь выбирает узел:

protected void TreeLibrary_SelectedNodeChanged(object sender, 
EventArgs e)
    {
        Label1.Text = "Вы выбрали категорию " + 
TreeLibrary.SelectedNode.Text;
    }

Можно программно раскрывать и закрывать узлы:

TreeView1.ExpandAll();
TreeView1.CollapseAll();

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

В следующем примере заполним значения элемента управления TreeView из базы данных Northwind. Родительские узлы — категории продуктов, которые заполняются данными о продуктах тогда, когда узел необходимо раскрыть:

<asp:TreeView ID="TreeViewCatProd" runat="server" 
ImageSet="BulletedList3" 
      OnTreeNodePopulate="TreeViewCatProd_TreeNodePopulate" 
ForeColor="DarkOliveGreen">
      </asp:TreeView>

public partial class Products : System.Web.UI.Page
{
  string connectionString = @"Data Source=.\SQLEXPRESS;Initial 
Catalog=Northwind;Integrated Security=True";

  protected void Page_Load(object sender, EventArgs e)
  {
    if (!Page.IsPostBack)
    {
      BindData();
    }
  }

Вспомогательная функция устанавливает соединение с базой данных и возвращает SqlDataReader — самый быстрый способ чтения данных:

protected SqlDataReader CreateSqlDataReader(string SelectQuery, 
string ConnectionString)
  {
    SqlConnection  Connection = new 
SqlConnection(ConnectionString);
      SqlCommand Command = new SqlCommand(SelectQuery, Connection);
    try
    {
      Command.CommandType = CommandType.Text;
      Command.Connection.Open();
      SqlDataReader reader = 
Command.ExecuteReader(CommandBehavior.CloseConnection);
      return reader;
    }
    catch
    {
      Connection.Close();
      return null;
    }
  }

При работе с базами данных важно перехватывать исключения:

protected void BindData()
  {
    TreeNode parentNode = null;
    SqlDataReader reader = CreateSqlDataReader("Select 
CategoryID,CategoryName from Categories", connectionString);
    if (reader!=null)
    {
      while (reader.Read())
      {
        parentNode = new 
TreeNode(reader["CategoryName"].ToString(), 
reader["CategoryID"].ToString());
        parentNode.Collapse();
        parentNode.PopulateOnDemand = true;
        parentNode.SelectAction = TreeNodeSelectAction.Expand;
        TreeViewCatProd.Nodes.Add(parentNode);
      }
      reader.Close();
    }
 }

Конструктор TreeNode может вызываться без параметров, но он перегружен. Вариант, который здесь используется, позволяет задать текст узла и значение Value (заполняется значением CategoryID ), которое необходимо, чтобы найти в базе продукты этой категории.

При раскрытии узла с категорией будет вызываться обработчик:

protected void TreeViewCatProd_TreeNodePopulate(object sender, 
TreeNodeEventArgs e)
  {
    TreeNode node = e.Node;
    if (node.PopulateOnDemand)
    {
      string command = string.Format("Select ProductID, 
ProductName from Products where CategoryID={0}", node.Value);
      SqlDataReader reader = CreateSqlDataReader(command, 
connectionString);
      node.ChildNodes.Clear();
      if (reader != null)
      {
        while (reader.Read())
        {
          TreeNode childNode = new 
TreeNode(reader["ProductName"].ToString());
          childNode.SelectAction = TreeNodeSelectAction.None;
          node.ChildNodes.Add(childNode);
        }
        node.Expand();
        reader.Close();
      }
    }
  }

TreeView позволяет не только показывать информацию, но ставить флажки рядом с узлами. Это полезно, если в нем содержится информация о товарах и пользователь может выбрать некоторые из них. Свойство ShowCheckBoxes допускает 5 значений: None, Root, Parent, Leaf, All:

ShowCheckBoxes="Leaf"

При этом рядом с узлами-листьями появляются флажки. Значение флажков можно прочитать программно:

<asp:XmlDataSource ID="XmlDataSource3" runat="server" 
DataFile="~/menu.xml"></asp:XmlDataSource>
<asp:TreeView ID="TreeMenu" runat="server" 
DataSourceID="XmlDataSource3" BackColor="#FFFBD6" 
   Font-Names="Verdana" Font-Size="0.8em" ForeColor="#990000" 
Height="78px"
   Width="415px" ShowCheckBoxes="Parent" 
OnTreeNodeCheckChanged="TreeMenu_TreeNodeCheckChanged" 
NodeWrap="True" PopulateNodesFromClient="False">
   <DataBindings>
      <asp:TreeNodeBinding DataMember="name" 
ValueField="#InnerText" />
      <asp:TreeNodeBinding DataMember="price" FormatString="{0} 
руб." TextField="#InnerText" ValueField="#InnerText" />
      <asp:TreeNodeBinding DataMember="description" 
TextField="#InnerText" />
      <asp:TreeNodeBinding DataMember="calories" 
FormatString="{0} калорий" TextField="#InnerText" />
      <asp:TreeNodeBinding DataMember="food" TextField="name" />
      <asp:TreeNodeBinding DataMember="pizza_menu" Text="Меню 
Пиццы" Value="Меню Пиццы" />
   </DataBindings>
</asp:TreeView>
<asp:Label ID="Label1" runat="server" ></asp:Label>

Флажки стоят у родительских узлов, потому что именно там находятся названия блюд. В обработчике можно динамически показывать сумму текущего заказа:

protected void TreeMenu_TreeNodeCheckChanged(object sender, 
TreeNodeEventArgs e)
    {
        decimal sumPrices=0.0M;
        if (TreeMenu.CheckedNodes.Count > 0)
        {
            Label1.Text = "";
            foreach (TreeNode node in TreeMenu.CheckedNodes)
            {
              sumPrices += decimal.Parse(node.ChildNodes[0].Value);
            }
            Label1.Text = sumPrices.ToString() +"<br>";
        }
    }

Цена записана в первом дочернем поле с индексом 0. При этом обращаться к свойству Text было бы неправильно, потому что там находится отформатированный текст, например, "306 руб.", который нельзя преобразовать в число.

< Лекция 10 || Лекция 11: 12345 || Лекция 12 >
Алексей Савельев
Алексей Савельев

https://technet.microsoft.com/en-us/library/ms143221(v=sql.105).aspx

Денис Прокофьев
Денис Прокофьев

Везде написано, что это самый независимый и простой в использовании навигационный элемент управления, что он работает сразу с web.sitemap и не требует определения SiteMapDataSource.

Моя карта сайта состоит из двух страниц, вложенных друг в друга. asp:Menu, asp:TreeView отбображаются как ожидалось, а вот asp:SiteMapPath - нет. Он не виден нигде. Однако на его месте формируется разметка: <span id="SiteMapPath1"><a href="#SiteMapPath1_SkipLink" style="position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden;">Проход по ссылкам навигации</a><a id="SiteMapPath1_SkipLink"></a></span> - т.е. элемент отрабатывает.

В словах xHTML это выглядит так: <asp:SiteMapPath ID="SiteMapPath1" runat="server" />. Причем не важно - внутри тега form или снаружи - всегда одинаково.

Т.к. другие нав. ЭУ работают через простой источник данных без ошибок, делаю вывод - карта составлена правильно. ИД: <asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />

Карта: <?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
  <siteMapNode url="~/L11_1_simplePage.aspx" title="Страница 1"  description="Простая страница 1." >
    <siteMapNode url="~/L11_1SimplePage2.aspx" title="Страница 2"  description="Простая страница 2" />
  </siteMapNode>
</siteMap>

Почему так происходит? Вроде делаю все по примерам. VS Community 2015. NetFramework в проекте: v4.0.30319