1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ツリー構造をなすクラスを作る(その2)

Last updated at Posted at 2023-12-17

Nuget-TreeStructures

ツリー構造の変更通知内容

次はObservableTreeNodeCollectionを使用してみます。

//使用するノードを定義
public class ObservableSampleNode: ObservableTreeNodeCollection<ObservableSampleNode> {
    public string Name { get; set; }
    public override string ToString() {
        return this.Name;
    }
}
Console.WriteLine("コレクションをN分木として組み立てる");

var nodesDic = "ABCDEFGHIJ".ToCharArray().Select(x => x.ToString())
    .ToDictionary(x => x, x => new ObservableSampleNode() { Name = x });
var root = nodesDic.Values.AssembleAsNAryTree(3);
//ツリーを表示
Console.WriteLine(root.ToTreeDiagram(x => x.Name));

EventHandler<StructureChangedEventArgs<ObservableSampleNode>> structreChangedHdlr = (s, e) => {
    Console.WriteLine($"sender:{s} \nTarget:{e.Target} TreeAction:{e.TreeAction} PreviousParentOfTarget:{e.PreviousParentOfTarget} OldIndex:{e.OldIndex} AncestorWasChanged:{e.AncestorWasChanged} DescendantWasChanged:{e.DescendantWasChanged}");
    if (e.AncestorWasChanged) {
        //祖先ノードに変更があった場合の情報を表示
        var info = e.AncestorInfo!;
        Console.WriteLine($"MovedTarget:{info.MovedTarget} OldIndex:{info.OldIndex} PreviousParentOfTarget:{info.PreviousParentOfTarget} RootWasChanged:{info.RootWasChanged}");
    }
    if (e.DescendantWasChanged) {
        //子孫ノードに変更があった場合の情報を表示
        var info = e.DescendantInfo!;
        Console.WriteLine($"Target:{info.Target} NodeAction:{info.NodeAction} OldIndex:{info.OldIndex} PreviousParentOfTarget:{info.PreviousParentOfTarget}");
    }
    Console.Write("\n");
};

PropertyChangedEventHandler propertyChangedHdlr = (s, e) => { Console.WriteLine($"sender:{s} Parent Changed.\n"); };

foreach (var node in root.Preorder()) {
    node.StructureChanged += structreChangedHdlr;
    node.PropertyChanged += propertyChangedHdlr;
}

イベント引数の説明を。

全てのノード共通で通知される情報に加え、
祖先ノードに変更があった場合 AncestorWasChanged は true となり、AncestorInfo が格納。
同様に子孫ノードに変更があった場合は DescendantWasChanged が true となり、DescendantInfo が格納されます。

削除時の通知

では、上記ツリーからnode D を削除します。

Console.WriteLine("node D を削除\n");
nodesDic["B"].RemoveChild(nodesDic["D"]);
//削除後のツリーを表示
Console.WriteLine(root.ToTreeDiagram(x => x.Name));

削除前
screenshot.3 - コピー.jpg

削除後
screenshot.5.jpg

出力コメント
screenshot.4.jpg

node A,B、node C,E,F,G、node D,H,I はそれぞれ同じ通知内容になっています。

node A,BDescendantWasChanged が true となって DescendantInfo が表示。
node C,E,F,G は、変更のあった node D の、祖先でも子孫でもないので AncestorWasChanged、DescendantWasChanged ともに False。
切り離された node D,H,IAncestorWasChanged が true となり AncestorInfo が表示されています

追加時の通知

次は先ほど削除した node D を node E の子ノードに加えます。

Console.WriteLine("node D を node E の子ノードに追加");
nodesDic["E"].AddChild(nodesDic["D"]);
//追加後のツリーを表示
Console.WriteLine(root.ToTreeDiagram(x => x.Name));

追加前
screenshot.5.jpg
追加後
screenshot.7 - コピー.jpg

出力コメント
screenshot.6.jpg

node A,B,E は子孫に変更があったので DescendantWasChanged が true となり、
node C,F,G は共にfalse、
node D,H,I は祖先に変更があったので AncestorWasChanged が true です。

移動時の通知

今度はツリー内でノードを移動させてみます。
node E を node C の子ノードに移動。

Console.WriteLine("node E を node C の子ノードに移動\n");
nodesDic["C"].AddChild(nodesDic["E"]);
//移動後のツリーを表示
Console.WriteLine(root.ToTreeDiagram(x => x.Name));

移動前
screenshot.7 - コピー (2).jpg

移動後
screenshot.9 - コピー.jpg

出力コメント
screenshot.8.jpg

TreeActionとNodeActionの違いですが、
TreeActionはツリー全体から見たAction、
NodeActionは各nodeから見たSubTreeにおけるActionです。

ツリー全体(node A)から見てnode E がツリー内を移動したので TreeAction は Move
node B から見てSubTreeから離れたので NodeAction は Deviate
node C から見てSubTree外から加わったので NodeAction は Join

ツリー内の移動なのでnode E,D,H,Iから見て RootWasChanged は False となります。

各イベントの発行順

現在のコードでは、
子ノードコレクションのイベントを購読していた場合、CollectionChangedEvent が先に発行されます。
その後、Parent プロパティの変更通知が発行され、レベルオーダーで StructureChanged イベントが発行されます。
最初のCollectionChangedが発行された時にはParentも既に設定済み、というのが理想なのでそれを実現してはいるのですが、処理過程でエラーが出た場合の処理を考えると妥協して変更した方がいいのかなぁという気もしてます。

まだ続く

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?