Windows Management Instrumentation - инфраструктура управления операционной системой, страница 8

  if (UpdateStatus != null)

     UpdateStatus (clr, s);

}

Для того, чтобы это заработало, надо:

¨  Создать DLL (добиться безошибочного ее построения),

¨  Обратиться к проекту Client, открыть MainForm.cs в режиме дизайна, выделить на форме разрабатываемый нами компонент, в окне свойств нажать кнопку Events,

¨  Найти свойство UpdateStatus, которое расположено в блоке Misc и совершить над ним двойной щелчок.

Категория Misc и свойство UpdateStatus появятся в дизайнере лишь в случае успеха в построении компонента ExplorerControl. Далее, вставьте в обработчик события тривиальный код, который отображает сообщение в статус строке.

private void explorer_UpdateStatus (Color clr, string msg)

{

  if (info.BackColor != clr)

     info.BackColor = clr;

  info.Text = msg;

}

Если вы захотите увидеть делегата, которого создал дизайнер в момент совершения двойного щелчка, то вы найдете его внутри скрытого кода (метода InitializeComponents). Код выглядит следующим образом.

this.explorer.UpdateStatus += new Library.ExplorerControl.StatusHandler(

  this.explorer_UpdateStatus);

Отныне все сообщения, приносимые делегатом события UpdateStatus, будут безотказно отображаться в строке состояния. Мы будем пользоваться этим и при создании других компонентов. Полезно назвать по именам всех участников процесса доставки сообщения (событие, делегата и функцию отклика). Сделайте это в качестве упражнения. Замечание: на рисунке ниже эта функциональность пока отсутствует.

Если с картинками и кодом вы справились, то запустив приложение, должны увидеть дерево, в котором присутствуют только диски. При выборе узла его изображение должно изменяться, как показано ниже.

Узлы дерева (кроме корневого) не имеют маркеров раскрытия, так как мы заполнили только один уровень вложенности. Теперь надо создать метод (назовем его AddItems), который опрашивает все папки, вложенные внутрь текущей и генерирует узлы дерева, опираясь на эту информацию.

private void AddItems (TreeNode node)

{

      //===== Получите информацию о текущем узле (node - используйте класс DirectoryInfo)

  //===== Здесь понадобится полный файловый путь узла node

  if (информация не существует - Floppy or CD не вставлен (Используйте метод Exists класса DirectoryInfo))

     return;

  DirectoryInfo[] dirs;

  try {Получите информацию о коллекции вложенных папок} catch { return; }

      //===== Лучше делать это в блоке try-catch, так как доступ к некоторым папкам закрыт

  uint hidden = (uint)FileAttributes.System | (uint)FileAttributes.Hidden;

      //===== Спрятанные и ситемные папки надо показывать только если опущен флаг bHide

      //===== Создайте цикл прохода по коллекции вложенных папок и вложите в него следующие 2 строки кода

     if (!bHide || ((uint)dir.Attributes & hidden) != hidden)

                 // Создаем и вставляем новый узел в коллекцию узлов узла node (одна строка кода !!!)

       // Используйте индексы изображений для папки 10, 11

}

В первом операторе только-что рассмотренного метода надо получить полный файловый путь к папке, соответствующей текущему узлу дерева. Если ориентироваться только на один уровень вложенности, то получить эту информацию довольно просто, но если вспомнить о произвольном уровне вложенности, то придется создать вспомогательный метод, который вычисляет полный путь. Здесь удобно и достаточно эффективно использовать рекурсию. Цепь рекурсивных вызовов позволяет подняться по дереву, начиная от текущего узла и заканчивая узлом, который находится в корне всего дерева. Ниже приводится это решение.

private string GetPath (TreeNode node)

{

  return node.Parent == root ? node.Text + '\\':

     Path.Combine (GetPath (node.Parent), node.Text);

}

Как видите, метод GetPath вызывает сам себя до тех пор, пока не доберется до корня дерева. Сам корень ("My Computer") нам не нужен, так как он портит стандартный файловый путь. Он введен только из уважения к традициям Microsoft. Класс Path специально создан для работы со строками текста, которые представляют собой файловые пути. Он имеет ряд удобных методов, которыми мы будем пользоваться и далее. Если вы успешно разобрались в логике, заложенной в методах GetPath и AddItems, то при запуске приложения увидите картину, подобную той, что показана ниже. Диски должны иметь маркеры раскрытия, а папки — нет. Почему? Потому, что узлы дерева, соответствующие им, пока пусты (пусты коллекции вложенных узлов).

Для того, чтобы пойти дальше, надо реализовать реакцию на начальную стадию раскрытия узла — функцию tree_BeforeExpand. Заготовка этой функции уже существует (мы создали ее как обработчик события BeforeExpand). Алгоритм таков: перед тем, как узел раскроется, надо продвинуться на один шаг вперед в процессе заполнения дерева.

private void tree_BeforeExpand (object sender, TreeViewCancelEventArgs e)

{

      //===== Получите ссылку на раскрываемый узел. Она спрятана в параметре типа TreeViewCancelEventArgs

  Cursor = Cursors.WaitCursor;   tree.BeginUpdate();  // Тормозим перерисовку

  if (узел раскрывается впервые (спросите Tag))

     AddSubItems (node); //===== Эта функция показана ниже

}

Для продвижения на один шаг вперед создадим специальный метод AddSubItems. Закончить начатый процесс следует в реакции на событие AfterExpand, иначе дерево так и не сможет закончить процесс перерисовки (ведь мы его заморозили).

private void AddSubItems (TreeNode node)

{

  foreach ( Узла n из коллекции узлов, вложенных в node)

     AddItems (n); // Выполняем действие, реализованнае ранее

      // Корректируем флаг, сигнализирующий факт заполнения коллекции (Tag)

}

private void tree_AfterExpand(object sender, TreeViewEventArgs e)

{

  tree.EndUpdate();  Cursor = Cursors.Default;

}

В настоящий момент дерево должно функционировать так, как и было задумано. Маркеры раскрытия должны присутствовать во всех непустых узлах. Непустыми считаются узлы, в которых вложеные другие узлы (диски в узле "My Computer", или папки в остальных узлах).

Слежение за файловой системой