C # TreeView дизайн - лучший способ отобразить древовидную структуру? - PullRequest
4 голосов
/ 06 февраля 2009

Я пытаюсь использовать TreeView для отображения древовидной структуры объектов. У меня есть дерево четырех типов объектов: Компания (корневой узел), Город, Магазин и Сотрудник.

Интерфейс предназначен для добавления / удаления городов / магазинов / сотрудников, поэтому TreeView необходимо обновить, чтобы отразить любые изменения.

Я задаюсь вопросом, как правильно заставить TreeView отображать древовидную структуру и получать обновления при ее изменении.

Я думаю, что объект Company должен иметь события, такие как company.CityAdded и company.CityRemoved, тогда какая оболочка, которую я помещаю вокруг TreeView, отвечает на эти события? Когда TreeView будет создан, в каждом городе / магазине / сотруднике будет узел. Каждый узел может затем реагировать на события узла, который он представляет в дереве.

Это правильная идея? Или есть лучший метод?

Ответы [ 5 ]

2 голосов
/ 07 февраля 2009

Я просто хотел добавить, что если WPF является вариантом для этого, он становится невероятно простым, используя иерархическую привязку данных и наблюдаемые коллекции. По сути, он обрабатывает все события и позволяет вам просто взаимодействовать с вашими бизнес-объектами.

1 голос
/ 06 февраля 2009

Похоже, вы на правильном пути. Я должен был сделать то же самое, несколько указателей, которыми я хотел бы поделиться:

  1. Сохранить ссылку на объект в свойстве тега TreeNode.

  2. Дайте каждому Treenode уникальное имя, которое может легко идентифицировать объект, например: хэш-код объекта, ID компании и т. Д.

Таким образом, вы можете легко находить и обновлять TreeNode при изменении состояния объекта. И когда пользователь выбирает узел, вы можете получить объект, который он представляет, из свойства Tag.

Удачи.

1 голос
/ 06 февраля 2009

Вы находитесь на правильном пути относительно концепции прослушивания событий (это стандартная схема издателя / подписчика).

Для актуального обновления древовидной структуры у меня есть два метода: AddOrUpdateTreeItem и RemoveTreeItem. Метод add или update делает то, что говорит, ищет элемент дерева (на основе пути) и обновляет его или добавляет его. Конечно, если модель обновляется в потоке, отличном от того, в котором была создана форма, вам необходимо выполнить маршалинг вызова, используя Control.BeginInvoke().

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

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

private void AddOrUpdateListItem(DomainModelObject item)
{
    ListViewItem li = lvwListView.Items[GetKey(item)];

    if (li == null)
    {
        li = new ListViewItem
                 {
                     Name = GetKey(item), 
                     Tag = item
                 };
        li.SubItems.Add(new ListViewItem.ListViewSubItem());
        li.SubItems.Add(new ListViewItem.ListViewSubItem());
        li.SubItems.Add(new ListViewItem.ListViewSubItem());
        li.ImageIndex = 0;
        lvwListView.Items.Add(li);
    }

    li.Text = [Itemtext];
    li.SubItems[1].Text = [Itemtext];
    li.SubItems[2].Text = [Itemtext];
    li.SubItems[3].Text = [Itemtext];
}

Вот пример того, как можно реализовать BeginInvoke():

public class MyForm : Form
{
    ...

    void data_Changed(object sender, DataChangedEventArgs e)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke(new EventHandler<DataChangedEventArgs>(data_Changed), sender, e);
            return;
        }

        AddOrUpdateListItem(e.DataItem);
    }

    ...
}
0 голосов
/ 08 февраля 2009

Ключом к шаблону публикации / подписки для обновлений является то, как обернуть информацию о том, что делать, когда срабатывает событие.

Когда объект, представляющий «Store X», обновляется новым именем и запускает событие, чтобы объявить об этом, какой объект потребляет событие?

Аналогично, когда добавляется Город Y, какой объект должен быть уведомлен о создании?

Один из распространенных подходов - иметь какой-то большой класс Uber-Manager, который обрабатывает весь процесс - он подписывается на все события и делает все.

Другой подход, который я использовал для хорошего эффекта, заключается в создании гораздо более простых объектов-оболочек / координаторов, которые обрабатывают только одну часть головоломки. Обычно я ставлю суффикс имени этих классов на «Editor».

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

Когда объект City обновляется, CityEditor реагирует на вызванное событие обновлением TreeNode. Когда объект City удален, CityEditor обеспечивает удаление узла из Treeview.

Когда новый объект Store добавляется в City, CityEditor может позаботиться о создании StoreEditor для координации обновлений на этом уровне. Аналогичным образом, когда Employee добавляется к Store, экземпляр EmployeeEditor обрабатывает обновления Treeview.

0 голосов
/ 06 февраля 2009

Вместо ...

  • Бизнес-объекты подписываются на события пользовательского интерфейса
  • Команды обновления пользовательского интерфейса
  • Бизнес-объекты обновляются при обновлении пользовательского интерфейса

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...