BindableWrapperSample - Houzkin/TreeStructures GitHub Wiki
BindableWrapper disposes all descendant nodes when it is disposed.
It also overrides the HandleRemovedChild method, calling the Dispose method for removed child nodes as well.
This allows handling resource release in derived classes by overriding protected void Dispose(bool disposing).
Disposed Wrapper nodes are all in a disassembled state.
Below is a comparison of Wrappers.
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;
}Define the above classes, and then compare the behavior of the Wrapper class and the BindableWrapper class.
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}"));
}
}
Disposed Wrapper nodes also cease to be synchronized with the source.