Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1447 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 15:

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

Совместная работа элементов TreeView и ListView в Проводнике файловой системы

При выполнении последнего примера видно, что войти в дочерний каталог можно, но вновь вернуться в родительский каталог нельзя. Чтобы сделать программу, совсем похожую на Проводник Windows, давайте объединим два последних примера, представленные классами DirectoryTreeView и DirectoryListView. Для порядка поместим коды классов в отдельных файлах проекта. Вот какая программа в итоге получилась.

using System;
using System.Drawing;
using System.Windows.Forms;
// Пространство имен для работы с каталогами
using System.IO;
    
namespace Test
{
    // Пользовательский класс построения дерева каталогов
    // как расширение библиотечного класса TreeView
    class DirectoryTreeView : TreeView
    {
        public DirectoryTreeView()  // Конструктор
        {
            // Создаем список иконок из внедренного ресурса
            ImageList imageList = new ImageList();
            // Порядок соблюдать - от него зависят индексы списка
            imageList.Images.Add(new Icon(GetType(),
                "Resource.CLSDFOLD.ICO"));  //0 - свернут
            imageList.Images.Add(new Icon(GetType(),
                "Resource.OPENFOLD.ICO"));  //1 - развернут
            imageList.Images.Add(new Icon(GetType(),
                "Resource.35FLOPPY.ICO"));  //2 - гибкий диск
            imageList.Images.Add(new Icon(GetType(),
                "Resource.CDDRIVE.ICO"));   //3 - жесткий диск
            imageList.Images.Add(new Icon(GetType(),
                "Resource.DRIVENET.ICO"));  //4 - папки
    
            // Используем наследуемые от TreeView свойства
            // Присоединяем список к свойству ImageList элемента TreeView
            this.ImageList = imageList;
            // В дереве в каждый момент времени может быть выделен только один узел
            this.ImageIndex = 0;        // Когда узел просто отображен (Collapsed)
            this.SelectedImageIndex = 1;// Когда узел выделен (Open)
    
            // Сканируем логические диски компьютера
            DriveInfo[] drives = DriveInfo.GetDrives(); // Статический метод
    
            // Строим дерево просмотра логических дисков и каталогов
            TreeNode selectedNode = null;
            foreach (DriveInfo drive in drives)
            {
                // Создаем очередной корневой узел для диска
                TreeNode nodeDrive = new TreeNode(drive.RootDirectory.Name);
                if (drive.RootDirectory.Name == @"C:\")
                    selectedNode = nodeDrive;
    
                // Назначаем узлу пиктограмму в зависимости от типа диска
                // Одинаковые изображения для свернутого и развернутого состояний
                if (drive.DriveType == DriveType.Removable)
                    nodeDrive.ImageIndex = nodeDrive.SelectedImageIndex = 2;
                else if (drive.DriveType == DriveType.CDRom)
                    nodeDrive.ImageIndex = nodeDrive.SelectedImageIndex = 3;
                else
                    nodeDrive.ImageIndex = nodeDrive.SelectedImageIndex = 4;
    
                // Добавляем узел диска в унаследованный TreeView
                this.Nodes.Add(nodeDrive);
                // Добавляем к корневому узлу подкаталоги ближайшего слоя
                // с помощью нашей теперь уже нерекурсивной функции
                AddDirectories(nodeDrive);
            }
    
            if (selectedNode != null)
                this.SelectedNode = selectedNode;
        }
    
        // Нерекурсивная функция добавления узлов подкаталогов
        void AddDirectories(TreeNode node)
        {
            node.Nodes.Clear(); // Очищаем коллекцию узлов на случай повторного
            // раскрытия уже ранее раскрытого и сформированного узла
    
            // Формируем полный путь для текущего каталога (узла)
            DirectoryInfo dirInfo = new DirectoryInfo(node.FullPath);
            // Объявляем ссылку на массив подкаталогов
            DirectoryInfo[] arrayDirInfo;
    
            // Если есть подкаталоги - безопасный код
            try
            {
                arrayDirInfo = dirInfo.GetDirectories();
            }
            catch
            {
                // Подкаталогов нет - выходим
                return;
            }
    
            // Добавляем к текущему узлу дочерний узел для каждого каталога
            foreach (DirectoryInfo dir in arrayDirInfo)
                node.Nodes.Add(new TreeNode(dir.Name));
        }
    
        // Переопределяем обработчик базового класса TreeView,
        // который срабатывает перед раскрытием пользователем
        // текущего узла, формируя ближайший слой дочерних узлов налету
        protected override void OnBeforeExpand(TreeViewCancelEventArgs args)
        {
            base.OnBeforeExpand(args);
    
            this.BeginUpdate(); // Замораживаем перерисовку дерева
    
            // Быстренько создаем ближайший слой подузлов для каждого
            // подузла раскрываемого узла, чтобы отображались
            // значки + на узлах слоя после раскрытия текущего
            foreach (TreeNode node in args.Node.Nodes)
                AddDirectories(node);
    
            this.EndUpdate();   // Освобождаем перерисовку дерева
        }
    }
}
Листинг 15.10 . Файл DirectoryTreeView.cs

using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
    
using System.Diagnostics;// Для класса Process
    
namespace Test
{
    // Расширение библиотечного класса ListView
    // для отображения файлов текущего каталога
    class DirectoryListView : ListView
    {
        public DirectoryListView()  // Конструктор
        {
        // Добавляем столбцы к ListView с нужной атрибутикой
        this.Columns.Add("Имя", 150, HorizontalAlignment.Left);
        this.Columns.Add("Размер", 100, HorizontalAlignment.Right);
        this.Columns.Add("Тип", 100, HorizontalAlignment.Left);
        this.Columns.Add("Изменен", 150, HorizontalAlignment.Left);
    
        // Заготавливаем две коллекции для значков файлов
        this.SmallImageList = new ImageList();
        this.LargeImageList = new ImageList();
        this.SmallImageList.ImageSize = new Size(16, 16);// По умолчанию
        this.LargeImageList.ImageSize = new Size(32, 32);
        }
    
        // Базовое поле для свойства
        string strDirectory;
    
        public string Directory // Свойство
        {
            // Аксессоры
            get { return strDirectory; }
            set
            {
            // Принимаем текущий каталог
            strDirectory = value;
    
            // Очищаем коллекции строк и значков
            this.Items.Clear();
            this.SmallImageList.Images.Clear();
            this.LargeImageList.Images.Clear();
    
            // Загружаем иконку каталога
            Icon icon = new Icon(this.GetType(), 
		"Resource.Folder.ico");
            this.SmallImageList.Images.Add(icon);// Индекс значка 0
            this.LargeImageList.Images.Add(icon);// Индекс значка 0
    
            // Создаем объект DirectoryInfo для текущего каталога
            DirectoryInfo dirInfo = new DirectoryInfo(strDirectory);
    
            // Формируем информацию о подкаталогах
            foreach (DirectoryInfo dir in dirInfo.GetDirectories())
              {
              // Создаем объект строки таблицы и первую ячейку "Имя"
              ListViewItem item = new ListViewItem(dir.Name);
              // Позиционируем строку на добавленный значок
              item.ImageIndex = 0;
              item.Tag = "dir";   // Пометили
              item.SubItems.Add("");// Вторая ячейка "Размер"
              item.SubItems.Add("Папка");// Третья ячейка "Тип"
              // Четвертая ячейка "Изменен"
              item.SubItems.Add(dir.LastAccessTime.ToString());
    
              Items.Add(item);// Добавили в коллекцию
              }
    
            int imageIndex = 1; // Счетчик индексов значков
    
            // Формируем информацию о файлах
            foreach (FileInfo file in dirInfo.GetFiles())
              {
              // Создаем объект строки таблицы и первую ячейку "Имя"
              ListViewItem item = new ListViewItem(file.Name);
              // Комбинируем полный путь к файлу
              string path = Path.Combine(file.DirectoryName, file.Name);
              // Получаем значек, ассоциированный с типом файла
              icon = Icon.ExtractAssociatedIcon(path);
              // Добавляем значек в коллекцию иконок элемента ListView
              this.SmallImageList.Images.Add(icon);// Индекс значка imageIndex
              this.LargeImageList.Images.Add(icon);// Индекс значка imageIndex
              // Позиционируем строку на добавленный значок
              item.ImageIndex = imageIndex++;
    
              // Вторая ячейка "Размер" с форматом
              string str = String.Format("{0},{1} КБ",
                        file.Length / 1000, file.Length % 1000);
              item.SubItems.Add(str);
    
              // Третья ячейка "Тип"
              string extension = Path.GetExtension(path).ToUpper() == 
			".EXE" ?
                        "Программа" : "Документ";
                    item.SubItems.Add(extension);
    
                    // Четвертая ячейка "Изменен"
                    item.SubItems.Add(file.LastWriteTime.ToString());
    
                    Items.Add(item);// Добавили в коллекцию
                }
            }
        }
    
        // Переопределяем обработчик класса Control нажатия кнопки мыши
        protected override void OnMouseDown(MouseEventArgs e)
        {
        base.OnMouseDown(e);
    
        // Циклически меняем свойство View на одно из 5 значений перечисления
        // Для смены представления задействуем правую кнопку мыши
        if (e.Button == MouseButtons.Right)
          this.View = (View)(((int)this.View + 1) % 5);// Деление по модулю 5
        }
    
        // Переопределяем обработчик класса ListView активации его элемента
        // с помощью двойного щелчка левой кнопки мыши или клавиши Enter
        protected override void OnItemActivate(EventArgs e)
        {
        base.OnItemActivate(e);
    
        if ((string)SelectedItems[0].Tag == 
		"dir")// Используем введенную ранее метку
            {
            // При щелчке на папке входим в нее
            this.Directory = Path.Combine(this.Directory, SelectedItems[0].Text);
            }
            else
            {
                // Иначе безопасно запускаем программу, 
                // ассоциированную с выделенным файлом или файлами
                foreach (ListViewItem item in this.SelectedItems)
                {
                    try
                    {
                        Process.Start(Path.Combine(this.Directory, item.Text));
                    }
                    catch { } // Ничего не делаем
                }
            }
        }
    }
}
Листинг 15.11 . Файл DirectoryListView.cs

using System;
using System.Drawing;
using System.Windows.Forms;
    
namespace Test
{
    // Класс приложения
    class MyExplorer : Form
    {
        // Объявляем ссылки-поля
        DirectoryTreeView tree;
        DirectoryListView list;
    
        public MyExplorer()    // Конструктор
        {
            // Настраиваем форму
            this.Text = "Наш элементарный Проводник";
            this.StartPosition = FormStartPosition.CenterScreen;
            this.Width *= 2;    // Увеличили ширину формы
            // Внедряем в сборку ресурс иконки формы
            this.Icon = new Icon(GetType(), "Resource.1.ICO");
    
            // Создаем экземпляр класса DirectoryTreeView
            tree = new DirectoryTreeView();
            // Привязываем к форме
            tree.Parent = this;
            // Приклеиваем слева
            tree.Dock = DockStyle.Left;
            // Регистрируем обработчик выделения узла
            tree.AfterSelect += new TreeViewEventHandler(tree_AfterSelect);
    
            // Создаем экземпляр класса DirectoryListView
            list = new DirectoryListView();
            // Привязываем к форме
            list.Parent = this;
            // Приклеиваем справа
            list.Dock = DockStyle.Right;
            // Устанавливаем начальный режим "Таблица"
            list.View = View.Details;
    
            // Предусматриваем поддержку изменения размеров формы
            WidthControl();
            this.Resize += new EventHandler(ElementaryExplorer_Resize);
        }
    
        // Делим форму между элементами
        void WidthControl()
        {
            int width = this.ClientSize.Width;
            tree.Width = width / 4;
            list.Width = width - tree.Width;
        }
    
        // При щелчке на каталоге показываем содержимое в list
        void tree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            list.Directory = e.Node.FullPath;
        }
    
        void ElementaryExplorer_Resize(object sender, System.EventArgs e)
        {
            // Делим форму между элементами
            WidthControl();
        }
    }
}
Листинг 15.12 . Файл MyExplorer.cs

using System.Windows.Forms;
        
namespace Test
{
    // Запуск
    class Program
    {
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.Run(new MyExplorer());
        }
    }
}
Листинг 15.13 . Файл Program.cs

Внешнее представление программы будет таким


Итак, мы видим, что спроектированный нами MyExplorer имеет такую же (ну, почти такую!) функциональность, что и стандартный Проводник Windows.

Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.

 

Как активировать код?