Skip to content

Instantly share code, notes, and snippets.

@killnine
Created September 27, 2012 17:19
Show Gist options
  • Save killnine/3795230 to your computer and use it in GitHub Desktop.
Save killnine/3795230 to your computer and use it in GitHub Desktop.
Asynchronous TreeView-builder Proof-Of-Concept
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace View
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
PopulateTree(SeedCategories());
}
/// <summary>
/// Makes up a bunch of categories for testing.
/// </summary>
/// <returns></returns>
private static IEnumerable<Category> SeedCategories()
{
IList<Category> categoryList = new List<Category>();
//Create a bunch of categories
for(int catId= 0; catId < 25; catId++)
{
Category category = new Category(catId, "category" + catId);
categoryList.Add(category);
}
return categoryList;
}
/// <summary>
/// Asynchronously populates the treeView in the UI. Sets the UI to indicate 'loading...',
/// followed by updating the TreeView once all the categories and subcategories have been
/// populated
/// </summary>
/// <param name="categories">List of categories to add to the treeView</param>
private void PopulateTree(IEnumerable<Category> categories)
{
//Set tree to 'loading' state
categoryTreeView.Nodes.Clear();
categoryTreeView.Nodes.Add("Loading...");
//Start the long, hard task of populating everything
Task<TreeNode[]> t = Task<TreeNode[]>.Factory.StartNew(() => PopulateTreeNodes(categories));
t.ContinueWith(x => UpdateUI(x.Result), TaskScheduler.FromCurrentSynchronizationContext());
}
/// <summary>
/// Goes through each category and populates its subcategories.
/// </summary>
/// <param name="categories">The categories.</param>
/// <returns>TreeNode array that can be added to the UI element later</returns>
private static TreeNode[] PopulateTreeNodes(IEnumerable<Category> categories)
{
IList<TreeNode> treeNodes = categories.Select(GetSubcategories).ToList();
return treeNodes.ToArray();
}
/// <summary>
/// Gets the subcategories, simulating a long-running process
/// </summary>
/// <param name="category">The category.</param>
/// <returns>Sub-category tree node</returns>
private static TreeNode GetSubcategories(Category category)
{
//Create some made-up variables to make it interesting
int sleepTime = category.Id * 10 < 250 ? category.Id * 10 : 250;
int numberOfSubcategories = category.Id < 5 ? category.Id : category.Id % 5;
//Sleep to imitate long-running process
Thread.Sleep(sleepTime);
//Create the actual TreeNode
TreeNode node = new TreeNode(category.Name);
for(int i =0; i < numberOfSubcategories; i++)
{
TreeNode childNode = new TreeNode("ChildNode" + category.Id + "_" + i);
node.Nodes.Add(childNode);
}
return node;
}
/// <summary>
/// Updates the TreeNode UI element.
/// </summary>
/// <param name="nodes">The nodes to add to the UI.</param>
private void UpdateUI(TreeNode[] nodes)
{
//Clear out previous 'Loading...' node
categoryTreeView.Nodes.Clear();
//Populate with new list of nodes, like a boss
categoryTreeView.Nodes.AddRange(nodes);
}
}
/// <summary>
/// Category class
/// </summary>
public class Category
{
public int Id { get; private set; }
public string Name { get; private set; }
public Category(int id, string name)
{
Id = id;
Name = name;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment