Windows Management Instrumentation. События в WMI. Библиотека классов MyWMI. Особенности работы с большим деревом, страница 8

Интерфейс IComparer имеет всего один метод Compare, который должен вернуть (–1, 0, +1) в зависимости от результата сравнения двух объектов (знакомо, не правда-ли?). Но мы добавим логику, которая вызвана особенностями форматирования данных. Введите в состав класса ExplorerControl новую статическую переменную, которая повысит читабельность дат, отделяя дату содания файла от времени. Напомним, что время также является частью даты (объекта класса DateTime).

  public static string dateSep = "     "; // Разделитель даты и времени

Введите в пространство имен Library (после класса ExplorerControl, это важно) коды нового класса. Он поможет разобраться в проблеме сортировки списка из четырех колонок.

class FileListComparer : IComparer

{

  public int col;    // Номер колонки

  public SortOrder order;  // Режим сортировки

  public FileListComparer() { col = 0; order = SortOrder.Ascending; }

  public string MyTrim (string s) // Вспомогательный метод (временно убирает лишние символы)

  {

    if (col == 1) // В этой колонке при сортировке надо отвязаться от буквы К (KiloBytes)

    {

      int id = s.IndexOf('K');

      if (id != -1)  // Если так, то размер дан в байтах и это надо учесть

      {

        s = s.Trim (new char[] {'K', ' '});

        s = (double.Parse(s) * 1000).ToString();

      }

    }

    if (col == 2) // В этой колонке хотим заменить на пробел разделитель dateSep. Он был введен для удобства чтения дат

      s = s.Replace(ExplorerControl.dateSep, " ");

    return s;

  }

  public int Compare (object x, object y)

  {

    int res = 0;

    string

      s1 = MyTrim (((ListViewItem)x).SubItems[col].Text),

      s2 = MyTrim (((ListViewItem)y).SubItems[col].Text);

    switch (col)

    {

    case 0: res = s1.CompareTo(s2); // В нулевой колонке расположены имена файлов ( текстовые строки)

      break;

    case 1: // В первой колонке расположены размеры файлов (double)

      res = // Напишите код сравнения вещественных чисел, спрятанных в строках текста s1 и s2 (Use Parse)

      break;

    case 2:   // Во второй и третьей колонках — даты (объекты DateTime)

    case 3:  // Напишите код сравнения дат

      res =         break;

    }

    if (order . . .  Режим сортировки по убыванию)

      // Измените результат res (Одна строка кода. Намек: ноль не боится изменения знака)

    return res;

  }

}

Особенности работы с большим деревом

Итак, интерфейс IComparer реализован и представлен миру классом FileListComparer. Мы задействуем его позже, когда будем развивать элемент типа ListView, а теперь пора подумать о дереве объектов файловой системы. В нем должен быть узел "My Computer", в который мы вложим все доступные логические диски. После этого в узлы, соответствующие дискам, мы вложим узлы, отображающие папки и т. д. Алгоритмы управления большими деревьями (а наше, как раз такое) довольно сложны и требуют достаточно высокой культуры программирования. Если задаться целью один раз (при запуске программы) заполнить все дерево, то из этого ничего хорошего не выйдет.

Сначала я написал рекурсивную функцию анализа и заполнения всего файлового дерева при начальном запуске приложения. Оказалось, что эта процедура занимает 5-7 минут, в течение которых приложение выглядит мертвым. Правда, после этого дерево раскрывает свои ветви мгновенно, потому что оно имеет информацию о всех своих ветвях. Если логических дисков и папок много (а в сетевой системе их очень много), то программа будет молчать очень долго. Кроме того, дерево потребует недопустимо много памяти.

Обычно используют другие варианты работы с большими деревьями. Один из них состоит в том, что при проверке объекта файловой системы (диска или папки) он не сканируется далеко вглубь. Дерево обгоняет пользователя лишь на один уровень вложенности узлов. Надо заполнить лишь один уровень (тот, который не виден пользователю). Если этого не сделать, то закрытый узел не будет иметь маркера раскрытия. Затем, когда пользователь действительно раскроет узел (это событие надо обработать), следует продвинуться вглубь дерева еще на один уровень вложенности. Раскрываемая же на данном шаге ветвь, уже наполнена реальными сущностями, так как это было выполнено на предыдущем шаге движения вглубь дерева.