The best answer was from BCProgramming , which provided a C# code sample as the example:
So I opened an O2 Platform SourceCodeEditor:
Clicked on Sample C#
and copied the BCProgramming response source code
into it:
The first attempt to compile the source code failed:
because the code-behind code is missing:
Which in this case can be easily fixed by adding the using O2.DotNetWrappers.ExtensionMethods reference and adding an TreeView here:
Next step is to create a test class and test method that will fire up the form:
Next step is to add the button
which when clicked adds the nodes:
Now that we have this working lets start refectoring the code, using the ExtensionMethods from the FluenSharp.BCL.dll library (available from Nuget).
I’m a big fan of REPL development, so the first extra feature I’m going to add is a link to open a C# REPL window with the current Form passed as parameter (see line 57 below):
which will make the form look like this (note the extra link):
and clicking on the link will open the REPL in a popup window:
Note how the first command on the REPL was return form1;
What that means is that we have access to that variable from our script, and that form1 variable is the Form created by the original C# class, ie. NodesTest.Form1
Also note that we have complete control over that Form object, and even have intelisense into its public properties, fields and methods:
for example the tvwTest TreeView object:
which we can manipulate in real time (for example to add new Node, change color and get all nodes)
Note how treeView.nodes() returned all nodes, and how (below) treeView.nodes(true) will return a recursive search of all nodes:
This means that (back into the original code we copied from reddit) we can remove these methods:
which are used from here:
with just (note how the result is the same):
Next we clear the treeView using tvwTest.clear()
and create the child nodes like this:
Since the idea is to add the node to the root when ParentId is 0, we can refactor the code like this:
And here is a confirmation that the refactored code behaves as the original (note the expandAll() call at the end, which save us to need to expand each node to check it)
To make the code easier to read, let’s remove the comments with the old code (I also changed like 76 to use the treeNode.get<T>() extension method):
And if you are into Linq we can replace the search with a dictionary:
The previous one looks to complex (and not optimized since we need to get all nodes all the time), so this version keeps an XRef of the articles added:
Here is a cleaner version:
I’m a big fan of Lambda methods, so here is version using them (note that the code below now handles the case when there is an invalid parent):
Here is a simpler version (by adding another lambda method called findParent)
Which can be further simplified to:
And here is the exact same code using functions (instead of Lamdba methods):
Let’s try this on the O2 C# REPL
In the previous example I was using a normal C# class and a code editor.
But for code samples/PoCs like this, I would normally use the O2 Platform C# REPL since it is a much faster and efficient code-development environment.
Since we have some data hold on external classes, I will create a simple C# file (saved to E:\O2\O2.Temp\5_22_2013\tmpCCF6.tmp.cs ) with just that data:
Then we open the C# REPL:
and add a reference to the TestData file, and invoke the TestData.GetTestData() static method:
Then add the TreeView and Button:
Then we add the lambda methods previously created, and we have a working PoC:
Lets add one more lambda method so that the tree population happens when the button is clicked:
Finally lets change the topPanel variable to come from a stand-alone form:
and now clicking on Execute will give us a popup Form:
with the PoC:
Note that you can also package this PoC has a stand-alone exe using
which will create a 902Kb file:
of the PoC form:
Code samples used in this post
1) original code
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace NodesTest { public partial class Form1 : Form { private class TestData { public TestData(int pNodeId, int pParent, String pText) { NodeId = pNodeId; ParentId = pParent; Text = pText; } public int NodeId { get; set; } public int ParentId { get; set; } public String Text { get; set; } } //static test data. private TestData[] testinfo = new TestData[] { new TestData(1, 0, "ID 1"), new TestData(2, 0, "ID 2"), new TestData(3, 1, "ID 3 Child 1 of ID 1 "), new TestData(4, 1, "ID 4 Child 2 of ID 1"), new TestData(5, 2, "ID 5 Child 1 of ID 2"), new TestData(6, 2, "ID 5 Child 2 of ID 2"), new TestData(7, 2, "ID 5 Child 3 of ID 2"), new TestData(8, 5, "ID 8 Child 1 of ID 5") }; public Form1() { InitializeComponent(); } public IEnumerable<TreeNode> getAllNodes(TreeView tvw) { foreach (TreeNode iterate in tvw.Nodes) { yield return iterate; foreach (TreeNode childiterate in getAllNodes(iterate)) { yield return childiterate; } } } public IEnumerable<TreeNode> getAllNodes(TreeNode tvw) { //iterate through all nodes... foreach (TreeNode iterateNode in tvw.Nodes) { yield return iterateNode; foreach (TreeNode childiterate in getAllNodes(iterateNode)) { yield return childiterate; } } } private void button1_Click(object sender, EventArgs e) { tvwTest.Nodes.Clear(); foreach (var iterate in testinfo) { TreeNode CreateNode = new TreeNode(iterate.Text); CreateNode.Tag = iterate; TreeNode ParentNode = null; //if the parentID is 0, then add it to the TreeView. if (iterate.ParentId != 0) { //if there is a parent, look through all the nodes, and find it. foreach (TreeNode IterateNode in getAllNodes(tvwTest)) { TestData grabdata = IterateNode.Tag as TestData; if (grabdata != null) { if (grabdata.NodeId == iterate.ParentId) { ParentNode = IterateNode; break; } } } } if (ParentNode == null) tvwTest.Nodes.Add(CreateNode); else ParentNode.Nodes.Add(CreateNode); } } } }
2) version using lamda
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace NodesTest { public partial class Form1 : Form { private class TestData { public TestData(int pNodeId, int pParent, String pText) { NodeId = pNodeId; ParentId = pParent; Text = pText; } public int NodeId { get; set; } public int ParentId { get; set; } public String Text { get; set; } } //static test data. private TestData[] testinfo = new TestData[] { new TestData(1, 0, "ID 1"), new TestData(2, 0, "ID 2"), new TestData(3, 1, "ID 3 Child 1 of ID 1 "), new TestData(4, 1, "ID 4 Child 2 of ID 1"), new TestData(5, 2, "ID 5 Child 1 of ID 2"), new TestData(6, 2, "ID 5 Child 2 of ID 2"), new TestData(7, 2, "ID 5 Child 3 of ID 2"), new TestData(8, 5, "ID 8 Child 1 of ID 5") }; public Form1() { InitializeComponent(); } public IEnumerable<TreeNode> getAllNodes(TreeView tvw) { foreach (TreeNode iterate in tvw.Nodes) { yield return iterate; foreach (TreeNode childiterate in getAllNodes(iterate)) { yield return childiterate; } } } public IEnumerable<TreeNode> getAllNodes(TreeNode tvw) { //iterate through all nodes... foreach (TreeNode iterateNode in tvw.Nodes) { yield return iterateNode; foreach (TreeNode childiterate in getAllNodes(iterateNode)) { yield return childiterate; } } } private void button1_Click(object sender, EventArgs e) { tvwTest.Nodes.Clear(); foreach (var iterate in testinfo) { TreeNode CreateNode = new TreeNode(iterate.Text); CreateNode.Tag = iterate; TreeNode ParentNode = null; //if the parentID is 0, then add it to the TreeView. if (iterate.ParentId != 0) { //if there is a parent, look through all the nodes, and find it. foreach (TreeNode IterateNode in getAllNodes(tvwTest)) { TestData grabdata = IterateNode.Tag as TestData; if (grabdata != null) { if (grabdata.NodeId == iterate.ParentId) { ParentNode = IterateNode; break; } } } } if (ParentNode == null) tvwTest.Nodes.Add(CreateNode); else ParentNode.Nodes.Add(CreateNode); } } } }
3) version using functions
1: using System;
2: using System.Collections.Generic;
3: using System.ComponentModel;
4: using System.Data;
5: using System.Drawing;
6: using System.Linq;
7: using System.Text;
8: using System.Windows.Forms;
9: using O2.DotNetWrappers.ExtensionMethods;
10:
11: namespace NodesTest
12: {
13: public class TestForm1 // add a test class
14: {
15: public void showForm() // create a first method to be invoked
16: {
17: new Form1().ShowDialog(); // start the dialog
18: }
19: }
20:
21: public partial class Form1 : Form
22: {
23: private class TestData
24: {
25: public TestData(int pNodeId, int pParent, String pText)
26: {
27: NodeId = pNodeId;
28: ParentId = pParent;
29: Text = pText;
30: }
31:
32: public int NodeId { get; set; }
33: public int ParentId { get; set; }
34: public String Text { get; set; }
35: }
36:
37: //static test data.
38: private TestData[] testinfo = new TestData[]
39: {
40: new TestData(1, 0, "ID 1"),
41: new TestData(2, 0, "ID 2"),
42: new TestData(3, 1, "ID 3 Child 1 of ID 1 "),
43: new TestData(4, 1, "ID 4 Child 2 of ID 1"),
44: new TestData(5, 2, "ID 5 Child 1 of ID 2"),
45: new TestData(6, 2, "ID 5 Child 2 of ID 2"),
46: new TestData(7, 2, "ID 5 Child 3 of ID 2"),
47: new TestData(8, 5, "ID 8 Child 1 of ID 5")
48: };
49: public Form1()
50: {
51: //InitializeComponent()
52: tvwTest = this.add_TreeView(); // Creating a TreeView
53: button1 = this.insert_Above(30) // Adding a Panel above
54: .add_Button("click me"); // Adding a Button
55: button1.top(5).Click += button1_Click; // Setting the Click event
56:
57: button1.append_Link("REPL Form", ()=> this.script_Me()).top(10);
58:
59: //O2Thread.mtaThread(()=>button1.click());
60: }
61:
62: public TreeView tvwTest { get; set; } // TreeView as an Property
63: public Button button1 { get; set; } // Button as an Property
64: public Dictionary<int, TreeNode> nodes_XRefs { get; set; }
65:
66: private TreeNode findParent(int parentId)
67: {
68: if (parentId ==0)
69: return tvwTest.rootNode();
70: return nodes_XRefs.value(parentId);
71: }
72: private void addItem(TreeNode parentNode, int id, string text)
73: {
74: if (parentNode.notNull())
75: {
76: var newNode = parentNode.add_Node(text,id);
77: nodes_XRefs.add(id, newNode);
78: }
79: }
80: private void populateTreeView()
81: {
82: tvwTest.clear();
83: nodes_XRefs = new Dictionary<int, TreeNode>();
84: foreach (var iterate in testinfo)
85: {
86: var parentNode = findParent(iterate.ParentId);
87: addItem(parentNode, iterate.NodeId, iterate.Text);
88: }
89: }
90: private void button1_Click(object sender, EventArgs e)
91: {
92: populateTreeView();
93: tvwTest.expandAll();
94: }
95:
96: }
97: }
4) class with TestData
using System; public class TestData { public int NodeId { get; set; } public int ParentId { get; set; } public String Text { get; set; } public TestData(int pNodeId, int pParent, String pText) { NodeId = pNodeId; ParentId = pParent; Text = pText; } public static TestData[] GetTestData() { return new TestData[] { new TestData(1, 0, "ID 1"), new TestData(2, 0, "ID 2"), new TestData(3, 1, "ID 3 Child 1 of ID 1 "), new TestData(4, 1, "ID 4 Child 2 of ID 1"), new TestData(5, 2, "ID 5 Child 1 of ID 2"), new TestData(6, 2, "ID 5 Child 2 of ID 2"), new TestData(7, 2, "ID 5 Child 3 of ID 2"), new TestData(8, 5, "ID 8 Child 1 of ID 5") }; } }
5) H2 script that consumes the TestData class and creates the stand-alone exe:
var topPanel = "PoC - Populate TreeView from data" .popupWindow(700,400); //var topPanel = panel.clear().add_Panel(); var tvwTest = topPanel.add_TreeView(); var button = tvwTest.insert_Right(200) .add_Button("click me").fill(); var testinfo = TestData.GetTestData(); var nodes_XRefs = new Dictionary<int, TreeNode>(); Func<int, TreeNode> findParent = (parentId)=>{ if (parentId ==0) return tvwTest.rootNode(); return nodes_XRefs.value(parentId); }; Action<TreeNode, int, string> addItem = (parentNode,id, text)=> { if (parentNode.notNull()) { var newNode = parentNode.add_Node(text,id); nodes_XRefs.add(id, newNode); } }; Action populateData = ()=>{ tvwTest.clear(); foreach (var iterate in testinfo) { var parentNode = findParent(iterate.ParentId); addItem(parentNode, iterate.NodeId, iterate.Text); } tvwTest.expandAll(); }; button.onClick(()=>populateData()); //O2File:E:\O2\O2.Temp\5_22_2013\tmpCCF6.tmp.cs