From 518e58d90de54a6d63f7af277fd9c8a4db968292 Mon Sep 17 00:00:00 2001 From: tznind Date: Fri, 22 Jan 2021 22:04:14 +0000 Subject: [PATCH] added docs on generic treeview --- UICatalog/Scenarios/TreeUseCases.cs | 84 ++++++++++++++++ UICatalog/Scenarios/TreeViewFileSystem.cs | 12 +++ docfx/articles/treeview.md | 111 +++++++++++++++++++++- 3 files changed, 202 insertions(+), 5 deletions(-) diff --git a/UICatalog/Scenarios/TreeUseCases.cs b/UICatalog/Scenarios/TreeUseCases.cs index 43cf3cee7..9a5358442 100644 --- a/UICatalog/Scenarios/TreeUseCases.cs +++ b/UICatalog/Scenarios/TreeUseCases.cs @@ -25,6 +25,8 @@ namespace UICatalog.Scenarios { new MenuBarItem ("_Scenarios", new MenuItem [] { new MenuItem ("_Simple Nodes", "", () => LoadSimpleNodes()), new MenuItem ("_Rooms", "", () => LoadRooms()), + new MenuItem ("_Armies With Builder", "", () => LoadArmies(false)), + new MenuItem ("_Armies With Delegate", "", () => LoadArmies(true)), }), }); @@ -101,6 +103,88 @@ namespace UICatalog.Scenarios { currentTree = tree; } + + + private abstract class GameObject + { + + } + private class Army : GameObject + { + public string Designation {get;set;} + public List Units {get;set;} + + + public override string ToString () + { + return Designation; + } + } + + private class Unit : GameObject + { + public string Name {get;set;} + public override string ToString () + { + return Name; + } + } + + private class GameObjectTreeBuilder : ITreeBuilder { + public bool SupportsCanExpand => true; + + public bool CanExpand (GameObject model) + { + return model is Army; + } + + public IEnumerable GetChildren (GameObject model) + { + if(model is Army a) + return a.Units; + + return Enumerable.Empty(); + } + } + + + private void LoadArmies(bool useDelegate) + { + var army1 = new Army() + { + Designation = "3rd Infantry", + Units = new List{ + new Unit(){Name = "Orc"}, + new Unit(){Name = "Troll"}, + new Unit(){Name = "Goblin"}, + } + }; + + if(currentTree != null) + Win.Remove(currentTree); + + var tree = new TreeView() + { + X = 0, + Y = 0, + Width = 40, + Height = 20 + }; + + if(useDelegate){ + tree.TreeBuilder = new DelegateTreeBuilder((o)=>o is Army a ? a.Units : Enumerable.Empty()); + } + else{ + tree.TreeBuilder = new GameObjectTreeBuilder(); + } + + Win.Add(tree); + + tree.AddObject(army1); + + currentTree = tree; + } + private void Quit () { Application.RequestStop (); diff --git a/UICatalog/Scenarios/TreeViewFileSystem.cs b/UICatalog/Scenarios/TreeViewFileSystem.cs index 775b4d70d..a46c7be86 100644 --- a/UICatalog/Scenarios/TreeViewFileSystem.cs +++ b/UICatalog/Scenarios/TreeViewFileSystem.cs @@ -26,6 +26,7 @@ namespace UICatalog.Scenarios { private MenuItem miColoredSymbols; private MenuItem miInvertSymbols; private MenuItem miUnicodeSymbols; + private MenuItem miFullPaths; private Terminal.Gui.Attribute green; private Terminal.Gui.Attribute red; @@ -52,6 +53,7 @@ namespace UICatalog.Scenarios { null /*separator*/, miColoredSymbols = new MenuItem ("_ColoredSymbols", "", () => ShowColoredExpandableSymbols()){Checked = false, CheckType = MenuItemCheckStyle.Checked}, miInvertSymbols = new MenuItem ("_InvertSymbols", "", () => InvertExpandableSymbols()){Checked = false, CheckType = MenuItemCheckStyle.Checked}, + miFullPaths = new MenuItem ("_FullPaths", "", () => SetFullName()){Checked = false, CheckType = MenuItemCheckStyle.Checked}, }), }); Top.Add (menu); @@ -171,6 +173,16 @@ namespace UICatalog.Scenarios { treeViewNodes.SetNeedsDisplay(); } + private void SetFullName() + { + miFullPaths.Checked = !miFullPaths.Checked; + + if(miFullPaths.Checked) + treeViewFiles.AspectGetter = (f)=>f.FullName; + else + treeViewFiles.AspectGetter = (f)=>f.Name; + } + private ITreeNode CreateSimpleRoot () { diff --git a/docfx/articles/treeview.md b/docfx/articles/treeview.md index aabdcb5c9..84a05e82c 100644 --- a/docfx/articles/treeview.md +++ b/docfx/articles/treeview.md @@ -96,10 +96,111 @@ tree.AddObject(myHouse); ``` -Alternatively you can simply tell the tree how the objects relate to one another by implementing `ITreeBuilder`. This is a good option if you don't have control of the data objects you are working with: - -``` -TODO -``` +Alternatively you can simply tell the tree how the objects relate to one another by implementing `ITreeBuilder`. This is a good option if you don't have control of the data objects you are working with. ## TreeView + +The generic `Treeview` allows you to store any object hierarchy where nodes implement Type T. For example if you are working with `DirectoryInfo` and `FileInfo` objects then you could create a `TreeView`. If you don't have a shared interface/base class for all nodes you can still declare a `TreeView`. + +In order to use `TreeView` you need to tell the tree how objects relate to one another (who are children of who). To do this you must provide an `ITreeBuilder`. + + +### Implementing ITreeBuilder + +Consider a simple data model that already exists in your program: + +```csharp +private abstract class GameObject +{ + +} +private class Army : GameObject +{ + public string Designation {get;set;} + public List Units {get;set;} + + + public override string ToString () + { + return Designation; + } +} + +private class Unit : GameObject +{ + public string Name {get;set;} + public override string ToString () + { + return Name; + } +} + +``` + +An `ITreeBuilder` for these classes might look like: + +```csharp + +private class GameObjectTreeBuilder : ITreeBuilder { + public bool SupportsCanExpand => true; + + public bool CanExpand (GameObject model) + { + return model is Army; + } + + public IEnumerable GetChildren (GameObject model) + { + if(model is Army a) + return a.Units; + + return Enumerable.Empty(); + } +} +``` + +To use the builder in a tree you would use: + +``` +var army1 = new Army() +{ + Designation = "3rd Infantry", + Units = new List{ + new Unit(){Name = "Orc"}, + new Unit(){Name = "Troll"}, + new Unit(){Name = "Goblin"}, + } +}; + +var tree = new TreeView() +{ + X = 0, + Y = 0, + Width = 40, + Height = 20, + TreeBuilder = new GameObjectTreeBuilder() +}; + + +tree.AddObject(army1); +``` + +Alternatively you can use `DelegateTreeBuilder` instead of implementing your own `ITreeBuilder`. For example: + +``` +tree.TreeBuilder = new DelegateTreeBuilder( + (o)=>o is Army a ? a.Units + : Enumerable.Empty()); +``` + +## Node Text and ToString + +The default behaviour of TreeView is to use the `ToString` method on the objects for rendering. You can customise this by changing the `AspectGetter`. For example: + +``` +treeViewFiles.AspectGetter = (f)=>f.FullName; +``` + + + +