C# TreeView 设计 - 最佳的展示树形结构的方式是什么?

4
我正在尝试使用TreeView显示对象的树形结构。我有四种类型的对象:公司(根节点)、城市、商店和员工。
界面被设计用于添加/删除城市/商店/员工,因此TreeView必须更新以反映任何更改。
我想知道正确的方法来获取TreeView显示树形结构,并在更改时接收更新。
我认为公司对象应该有事件,例如company.CityAdded和company.CityRemoved,然后无论我在TreeView周围放置什么包装器都会响应这些事件?当TreeView被建立起来后,每个城市/商店/员工都将有一个节点。然后,每个节点都可以响应它在树中所代表的节点的事件。
这是正确的想法吗?还是有更好的方法?
5个回答

2
我只想补充一点,如果WPF是可选的话,使用分层绑定和可观察集合会变得非常简单。它基本上为您处理了所有的事件处理工作,并且让您与业务对象进行交互。

1

听起来你走在了正确的道路上。我曾经做过类似的事情,这里有几个要点想和你分享:

  1. 将对象引用存储在TreeNode标记属性中。

  2. 为每个Treenode分配一个唯一的名称,可以轻松地识别一个对象,例如:对象哈希码、公司ID等。

这样,当对象状态发生变化时,您可以轻松地找到并更新TreeNode。当用户选择一个节点时,您可以从Tag属性中获取它所代表的对象。

祝你好运。


1

你对事件监听的概念理解得很好(这是一个标准的发布/订阅模式)。

对于树形视图的实际更新,我倾向于有两个方法:AddOrUpdateTreeItemRemoveTreeItem。添加或更新方法会查找树形项目(基于路径)并更新或添加它。当然,如果模型在创建表单的线程之外的线程上进行更新,则需要使用Control.BeginInvoke()调用。

如果你正在加载完整的树或其他东西,这种方法可能会有点慢,因此你可能需要另一种初始填充方法,并在后续更新中使用我描述的概念。

我也会在列表视图中采用同样的方法,下面是一个典型的例子。添加树形项时的主要区别在于,您可能需要添加父节点以添加请求的节点,这使得它有点递归性。试试看。

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);
    }

    ...
}

+1 提到 BeginInvoke()。您可能需要修改示例以显示它。 - Matt Jordan

0

与其让业务对象订阅UI事件,

  • 命令更新UI
  • 当UI更新时,业务对象也会被更新

...你也可以反过来做(即命令更新业务对象树,从而导致UI相应地更新)。


0
发布/订阅模式的关键部分是如何包装事件触发时要执行的操作信息。
当代表“商店X”的对象使用新名称进行更新并触发事件以宣布已发生此情况时,哪个对象会消耗该事件?
同样地,当添加城市Y时,应通知哪个对象进行创建?
一种常见的方法是拥有某种大型超级管理器类来处理整个过程-它订阅所有事件并执行所有操作。
另一种方法,我已经成功使用的方法是创建更简单的包装器/协调器对象,只处理谜题的一部分。通常,我会在这些类的名称后缀中加上“Editor”。
因此,您可以拥有一个CityEditor类,其构造函数接受City对象和表示该对象的TreeNode。 CityEditor将订阅City对象和TreeNode上的事件,并负责使用标题填充TreeNode并选择图标。
当城市对象更新时,CityEditor 通过更新 TreeNode 来响应触发的事件。当城市对象被移除时,CityEditor 确保节点从 Treeview 中移除。
当新的商店对象添加到 City 中时,CityEditor 可以负责创建一个 StoreEditor 来协调该级别的更新。同样地,当将 Employee 添加到 Store 中时,EmployeeEditor 的实例处理 Treeview 的更新。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接