BindableWrapperSample_ja - Houzkin/TreeStructures GitHub Wiki

HierarchyWrapperとBindableHierarchyWrapperの違いは以下です。

Wrapper \ 動作 Dispose 子ノードコレクションの変更通知
HierarchyWrapper 定義なし Childrenプロパティ呼び出し時
BindableHierarchyWrapper 対象と子孫 随時

BindableWrapper.Dispose()

BindableWrapperはDisposeされることで子孫ノードも含めてDisposeされます。
また、HandleRemovedChildメソッドをoverrideしており、削除された子ノードに対してもDisposeメソッドを呼び出しています。
これにより、派生先でリソースの開放が必要な場合でも、protected void Dispose(bool disposing)をoverrideすることで対処可能です。

DisposeされたWrapperノードは全て分解された状態になります。 以下、Wrapperの比較。

public interface IMemberNode {
	string MemberName { get; }
	int Followers { get; }
}
public class ObservableMemberNode : ObservableGeneralTreeNode<ObservableMemberNode>, IMemberNode {
	public ObservableMemberNode(string name){
		MemberName = name;
		this.StructureChanged += Member_StructureChanged;
	}

	private void Member_StructureChanged(object? sender, StructureChangedEventArgs<ObservableMemberNode> e) {
		if(e.IsDescendantChanged && e.DescendantInfo!.SubTreeAction != TreeNodeChangedAction.Move){
			this.RaisePropertyChanged(nameof(Followers));
		}
	}

	public string MemberName { get; }
	public int Followers => this.Preorder().Count() - 1;
}

上記クラスを定義したうえで、WrapperクラスとBindableWrapperクラスの挙動を比較してみます。

public class MemberWrapper<TSrc> : TreeNodeWrapper<TSrc,MemberWrapper<TSrc>> where TSrc:class,ITreeNode<TSrc>,IMemberNode{

	public MemberWrapper(TSrc member) : base(member) { }

	protected override MemberWrapper<TSrc> GenerateChild(TSrc sourceChildNode) {
		return new MemberWrapper<TSrc>(sourceChildNode);
	}

	public string MemberName=>Source.MemberName;

	public int Followers => Source.Followers;

	public int WrappingFollowers => this.Preorder().Count() - 1;
}
public class BindableMemberWrapper<TSrc>:BindableTreeNodeWrapper<TSrc,BindableMemberWrapper<TSrc>>
where TSrc:class, ITreeNode<TSrc>,IMemberNode{ 

	public BindableMemberWrapper(TSrc member):base(member){ }

	protected override BindableMemberWrapper<TSrc> GenerateChild(TSrc sourceChildNode) {
		return new BindableMemberWrapper<TSrc>(sourceChildNode);
	}

	public string MemberName => Source.MemberName;

	public int Followers => Source.Followers;

	public int WrappingFollowers => this.Preorder().Count() - 1;
}

internal class SampleE {
	public static void Method(){
		var members = "ABCDEFGHIJ".ToCharArray().Select(x=>x.ToString()).ToDictionary(x => x, x => new ObservableMemberNode(x));

		var memberRoot = members.Values.AssembleAsNAryTree(2);

		var wrpMemberRt = new MemberWrapper<ObservableMemberNode>(memberRoot);

		var dispoWrpMemberRt = new BindableMemberWrapper<ObservableMemberNode>(memberRoot);

		Console.WriteLine("initial state of Wrapper");
		Console.WriteLine(wrpMemberRt.ToTreeDiagram(x => $"name:{x.MemberName}, Followers:{x.Followers}"));

		Console.WriteLine("initial state of BindableWrapper.");
		Console.WriteLine(dispoWrpMemberRt.ToTreeDiagram(x => $"name:{x.MemberName}, Followers:{x.Followers}, IsDisposed:{x.IsDisposed}"));

		var wrpB = wrpMemberRt.Preorder().First(x => x.MemberName == "B");
		var dspWrpB = dispoWrpMemberRt.Preorder().First(x=> x.MemberName == "B");

		Console.WriteLine("remove node B\n");
		memberRoot.Levelorder().First(x => x.MemberName == "B").TryRemoveOwn();

		Console.WriteLine("each root wrappers");
		Console.WriteLine(wrpMemberRt.ToTreeDiagram(x => $"name:{x.MemberName}, Followers:{x.Followers}"));
		Console.WriteLine(dispoWrpMemberRt.ToTreeDiagram(x => $"name:{x.MemberName}, Followers:{x.Followers}, IsDisposed:{x.IsDisposed}"));


		Console.WriteLine("each nodeB wrappers");
		Console.WriteLine(wrpB.ToTreeDiagram(x => $"name:{x.MemberName}, Followers:{x.Followers}"));
		Console.WriteLine(dspWrpB.ToTreeDiagram(x => $"name:{x.MemberName}, Followers:{x.Followers}, IsDisposed:{x.IsDisposed}"));


		Console.WriteLine("Dispose nodeC wrapper");
		dispoWrpMemberRt.Preorder().First(x => x.MemberName == "C").Dispose();
		Console.WriteLine(dispoWrpMemberRt.ToTreeDiagram(x => $"name:{x.MemberName}, Followers:{x.Followers}, IsDisposed:{x.IsDisposed}"));
	}
}

screenshot 31 screenshot 32

破棄されたWrapperノードはソースとの連動も停止します。

BindableWrapper.Children.CollectionChanged

HierarchyWrapper.Childrenの変更は、プロパティ取得時に更新されます。
BindableHiererchyWrapper.Childrenプロパティは変更を即時反映します。

var tree = "ABCDEFG".ToCharArray().Select(x => x.ToString()).AssembleAsNAryTree(2,
	x => new ObservableOtherHierarchy(x) as OtherHierarchy,
	x => x.Nests,
	(p, c) => p.Nests.Add(c));

var Wrpr = new OtherHierarchyWrapper(tree);
var BWrpr = new BindableOtherHierarchyWrapper(tree);

((INotifyCollectionChanged)Wrpr.Children).CollectionChanged += (s, e) => Console.WriteLine("Wrpr.Children collection changed"); 

((INotifyCollectionChanged)BWrpr.Children).CollectionChanged += (s, e) =>  Console.WriteLine("BWrpr.Children collection changed");

tree.Nests.Add(new OtherHierarchy("H"));
//BWrpr.Children collection changed

Console.WriteLine(BWrpr.ToTreeDiagram(x => x.SourceName));
/*
A
├ B
│ ├ D
│ └ E
├ C
│ ├ F
│ └ G
└ H
	* */
Console.WriteLine(Wrpr.ToTreeDiagram(x => x.SourceName));
/*
//Wrpr.Children collection changed
A
├ B
│ ├ D
│ └ E
├ C
│ ├ F
│ └ G
└ H 
	* */
⚠️ **GitHub.com Fallback** ⚠️