4

オブジェクトのツリー構造を表示するために TreeView を使用しようとしています。Company (ルート ノード)、City、Store、Employee の 4 種類のオブジェクトのツリーがあります。

インターフェイスは、都市/店舗/従業員を追加/削除するように設計されているため、変更を反映するために TreeView を更新する必要があります。

TreeView を取得してツリー構造を表示し、変更時に更新を受け取る正しい方法について疑問に思っています。

Company オブジェクトには company.CityAdded や company.CityRemoved などのイベントが必要だと考えていますが、TreeView の周りに配置したラッパーはこれらのイベントに応答しますか? TreeView が構築されると、都市/店舗/従業員ごとにノードが作成されます。その後、各ノードは、ツリー内でそれが表すノードのイベントに応答できます。

それは正しい考えですか?それとももっと良い方法がありますか?

4

5 に答える 5

2

WPF がこれのオプションである場合、階層的なデータバインディングと監視可能なコレクションを使用すると、信じられないほど簡単になることを追加したかっただけです。基本的にすべてのイベント処理を行い、ビジネス オブジェクトと対話するだけです。

于 2009-02-07T15:23:03.270 に答える
1

イベントをリッスンするという概念については、正しい方向に進んでいます (これは、標準的なパブリッシャー/サブスクライバーのパターンです)。

ツリービューを実際に更新するには、 と の 2 つの方法を使用する傾向が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);
    }

    ...
}
于 2009-02-06T19:02:57.897 に答える
1

あなたは正しい道を進んでいるように聞こえます。私は同様のことをしなければなりませんでした。いくつかのポイントを共有したいと思います:

  1. オブジェクト参照を TreeNode タグ プロパティに格納します。

  2. 各 Treenode に、オブジェクトを簡単に識別できる一意の名前を付けます。たとえば、オブジェクト ハッシュコード、会社 ID などです。

このようにして、オブジェクトの状態が変化したときに TreeNode を簡単に見つけて更新できます。ユーザーがノードを選択すると、それが表すオブジェクトを Tag プロパティから取得できます。

幸運を。

于 2009-02-06T19:09:27.930 に答える
0

それ以外の ...

  • ビジネス オブジェクトは UI イベントにサブスクライブします
  • コマンドは UI を更新します
  • UI の更新時にビジネス オブジェクトが更新される

...逆の方法で実行することもできます (つまり、コマンドがビジネス オブジェクトのツリーを更新し、その結果、対応する UI が更新されます)。

于 2009-02-06T19:14:49.170 に答える
0

更新のパブリッシュ/サブスクライブ パターンの鍵の 1 つは、イベントがトリガーされたときに何をすべきかという情報をラップする方法です。

「Store X」を表すオブジェクトが新しい名前で更新され、これが発生したことを通知するイベントを発生させる場合、どのオブジェクトがイベントを消費しますか?

同様に、都市 Y が追加された場合、どのオブジェクトに作成を通知する必要がありますか?

一般的なアプローチの 1 つは、プロセス全体を処理するある種の大規模な uber-manager クラスを用意することです。これは、すべてのイベントをサブスクライブし、すべてを実行します。

別のアプローチとして、私が効果的に使用した方法として、パズルの 1 つの部分だけを処理する、より単純なラッパー/コーディネーター オブジェクトを作成する方法があります。通常、これらのクラスの名前には " Editor" という接尾辞を付けます。

したがって、コンストラクターがオブジェクトとそのオブジェクトを表す のCityEditor両方を取るクラスを持つことができます。は、オブジェクトと の両方のイベントをサブスクライブし、にキャプションを入力してアイコンを選択します。CityTreeNodeCityEditorCityTreeNodeTreeNode

City オブジェクトが更新されると、CityEditorは を更新することによって、トリガーされたイベントに応答しTreeNodeます。City オブジェクトが削除されると、CityEditorはノードが から削除されていることを確認しますTreeview

新しい Store オブジェクトが に追加されるとCity、 はそのレベルで更新を調整するためCityEditorに を作成することができます。StoreEditor同様に、Employeeが に追加されるとStore、 のインスタンスが のEmployeeEditor更新を処理しますTreeview

于 2009-02-08T09:20:07.730 に答える