Click here to Skip to main content
11,496,146 members (416 online)
Click here to Skip to main content

FastTree and FastList

, 6 Oct 2014 LGPL3 16.4K 433 46
Fast and flexible replacing of standard WinForm’s controls: ListBox, CheckedListBox and TreeView.
The site is currently in read-only mode for maintenance. Posting of new items will be available again shortly.

                   

Introduction

The library presents two controls FastList and FastTree.

These controls are intended to replace standard WinForm’s controls: ListBox, CheckedListBox and TreeView.

Because usually I work with big data sets and I need perfect performance, these controls implement only virtual mode as fastest way of data receiving. The controls do not store text, color, icon, etc of items. All these data are passed into controls via events or overridden methods. So you need to store your data outside of the control. The controls store only service data such as: current checkbox state, selection state and collapsed/expanded state.

When I developed the controls, I pursued following goals:

  1. The control must be able to display big data set. By design no less than 1mln items – without lags.
  2. When data are changed, control must be able to rebuilding without lags and blinking. All secondary previous states (checkboxes, selection, expanding) must be saved after rebuilding.
  3. The control must implement virtual mode and do not take large amount of memory.
  4. The control must be flexible and allow be easy extending and inheriting.
  5. The control must contain wide set of events with cancelling ability. Each user’s action can be programmatically cancelled (selection, unselection, changing of checkbox state, expanding, collapsing, etc).
  6. Multiselection, checkboxes, icons.
  7. Wide set of customizing: coloring, custom height of items, custom item drawing, intending, visibility.
  8. Built-in drag&drop supporting.

All these requirements were implemented.

General design

The FastTree and FastList are inherited from one base class called FastListBase.

The FastListBase inherits standard UserControl and implements main functionality: drawing, scrolling, mouse and keyboard handlers, calculations of coordinates, etc. You can immediately inherit your controls from the FastListBase if you need maximum of flexibility and/or extension.

The FastListBase draws vertical list of the items. It does not know anything about data structure. It simply draws linear list of items, wherein each item has own left intending and own height.

Also FastListBase does not contain any events (except inherited from UserControl, of course). All data it receives via virtual methods, such as string GetItemText(int itemIndex), etc.

Virtual methods instead of events allow getting maximum of performance, because we do not pay for event calling. If subclass will not override the method, FastListBase will use default value, returned by own virtual method.

Also FastListBase stores some specific data, such as HashSet<int> of selected item indices and HashSet<int> of checked item indices. The FastListBase calculates coordinates of each item and stores it too.

The FastList is tiny wrapper over FastListBase. This class overrides virtual methods of the FastListBase and calls user events there. So FastList has one difference from FastListBase: it contains events.

The FastTree is thicker wrapper over FastListBase because it contains specific logic for tree. It overrides virtual methods and calls events too, but somewhere adds own code. Also it contains additional methods and events for tree data structure.

Usage of FastList

Simplest way to use FastList – drag it to form, and handle event ItemTextNeeded. In handler you need to return text of item by item index.

For example:

        private void fl_ItemTextNeeded(object sender, StringItemEventArgs e)
        {
            e.Result = list[e.ItemIndex];//where list - is your data
        }

 

Also you need to define count of items. You can assign property ItemCount in design mode or at runtime. When ItemCount is assigning, it calls protected method Build() to recalculate coordinates of drawn items.

Note: If your data was changed but count of items remains the same – simply call fastList.Invalidate(). Because FastList does not store data, it will take data from events and will show actual data after repainting. Only if count of items was changed – set ItemCount property.

More examples of FastList usage – see in Tester application.

Checkboxes

There are two mode of checkboxes. By default, FastList stores checkbox states by oneself, in internal storage CheckedItemIndex.

But if you assigned handler to ItemCheckStateNeeded, the control switches to virtual checkboxes mode. In this mode you need to return check state of item in handler of ItemCheckStateNeeded event.

Also, you can process state changing in handler of event ItemCheckedStateChanged.

Usage of FastTree

FastTree is more complex to usage because it requires tree data structure.

To start tree building, call public method void Build(object root), where root – is root object of your tree. The FastTree does not allow multiple roots, so all your data must be inside of root object (however root node can be hidden by ShowRootNode property).

Note: Root object is needed only to get tree data from your structures. The FastTree does not require some specific type of root, it can be instance of any type, or even null. But in future, in event handlers, you must return children or text for given object.

Next there is two ways: usage of IEnumerable or usage of event NodeChildrenNeeded.

Way 1: Handler of NodeChildrenNeeded

If you assigned handler to event NodeChildrenNeeded, the FastTree will call this event to receive children of given node. In this case you need to return IEnumerable of child objects from the handler for given parent object.

For example, building of tree of directories:

        ft.Build(@"c:\") //build tree using string "c:\" as root object
        ...

        private void ft_NodeChildrenNeeded(object sender, NodeChildrenNeededEventArgs e)
        {
            var path = e.Node as string;
            e.Children = Directory.GetDirectories(path);//return subdirectories of parent path
        }

        private void ft_NodeTextNeeded(object sender, FastTreeNS.StringNodeEventArgs e)
        {
            var path = e.Node as string;
            e.Result = Path.GetDirectoryName(path);//return name of directory as text of node
        }

Here we get path of parent directory and return list of subdirectories of it.

Way 2: IEnumerable interface

Another way to build tree – to use IEnumerable interface. This mode is enabled by default if handler of NodeChildrenNeeded is not assigned.

The idea is that data objects implement IEnumerable of its children. The FastTree will try to cast node to IEnumerable. And if the interface is presented – will get children from it. Otherwise – it will terminal node.

If you use this way, you need only call method void Build(object root) to build tree. Other tree nodes will be built automatically.

Also you can handle NodeTextNeeded event to draw some specific text for the nodes. But if NodeTextNeeded is not assigned, the FastTree will use ToString() method of node objects.

Note: If text of some nodes was changed, you need only call fastTree.Invalidate() method to refresh the control. But if structure of data (for example count of children) was changed – you must to call method Build(object root) to reflect data changes. All previous selected/checked/expanded states will be automatically restored.

More examples of FastTree usage – see in Tester application.

Checkboxes

There are two mode of checkboxes. By default, FastTree stores checkbox states by oneself, in internal storage.

But if you assigned handler to NodeCheckStateNeeded, the control switches to virtual checkboxes mode. In this mode you need to return check state of node in handler of NodeCheckStateNeeded event.

Also, you can process state changing in handler of event NodeCheckedStateChanged.

Useful events, properties and methods

Events NodeTextNeeded and ItemTextNeeded - Handle this event to assign text to the node/item.

Event NodeChildrenNeeded – can return children of the node.

Event NodeCheckStateNeeded and ItemCheckStateNeeded - can return checkbox state of the node/item.

Events NodeIconNeeded and ItemIconNeeded – returns image for icon of the node/item.

Events NodeHeightNeeded and ItemHeightNeeded. Handle this event if you needed individual height of items. If handler was not assigned – ItemHeightDefault will be used. Note, that you need to call Build() method if height of nodes was changed.

Events NodeBackColorNeeded, NodeForeColorNeeded, ItemBackColorNeeded, ItemForeColorNeeded – are used to set foreground and background color of the nodes/items.

Wide set of events: CanUnselectNodeNeeded, CanSelectNodeNeede, CanCheckNodeNeeded, etc – these permitting events can cancel appropriate user actions.

Events NodeCheckedStateChanged, NodeExpandedStateChanged, NodeSelectedStateChanged, ItemCheckedStateChanged, ItemExpandedStateChanged, ItemSelectedStateChanged – informs that node/items state was changed.

Events NodeDrag, DragOverNode, DropOverNode, ItemDrag, ItemOverItem, ItemDropOverItem – these events are occurred when user start drag/drag over node/drop node. Note that FastTree and FastList supports virtual data model. So if user drag item into the control, outer event handler must to change its data appropriate to dragging result, and call Build() method to rebuild the control. More examples see in FastListDropItemSample and FastListDragItemSample.

Property AllowDragItems - enables Drag&Drop of items.

Events PaintNode and PaintItem – handle this event if you want to make custom drawing of the node/item.

Property Nodes – list of all visible nodes.

Properties ExpandedNodes, SelectedNodes, CheckedNodes – lists of expanded/selected/checked nodes.

Properties SelectedItemIndex, CheckedItemIndex – hashsets of selected/checked item indicies.

Peroperty MultiSelect – enables multiselection.

Property ItemCount – get/set item count of the FastList.

Property ItemInterval - distance between items (in pixels).

Property NodeHeightDefault, ItemHeightDefault – default height of the node/item (in pixels).

Properties ShowIcons, ShowCheckBoxes – shows icons/checkboxes

Method Build(object root) – rebuild tree structure. Call it if structure of the tree was changed. Do not call it if only text of nodes was changed (call Invalidate() in this case).

Hotkeys

  • Up, Down, PageUp, PageDown, Home, End – select next/previous/first/last node/item.
  • (Up, Down, PageUp, PageDown, Home, End) + Ctrl – scrolls the control.
  • Enter, Space – changes checkbox state if ShowCheckBoxes enabled, expands/collapses node otherwise.
  • Mouse Click – select node/item.
  • Mouse Click + Shift – select item’s range (if Multiselection is enabled).
  • Mouse Click + Ctrl – add selected node/item (if Multiselection is enabled).
  • Mouse Drag&Drop - drag&drop
  • Mouse DblClick - expands/collapses node.
  • Mouse wheel – scrolls the control.
  • Ctrl + A – selects all nodes/items.

Performance

Up to 100 000 000 items for FastList. Up to 10 000 000 subnodes per node for FastTree.

History

  • 18 Sep 2014 - First release.
  • 20 Sep 2014 - Virtual checkboxes mode was added. Samples FastListVirtualCheckboxesSample and FastTreeDragAndDropSample were added.
  • 23 Sep 2014 - Memory usage was improved, stress tests were added.
  • 06 Okt 2014 - HotTracking and AllowSelectItems properties were added

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author

Pavel Torgashov
Software Developer Freelancer
Ukraine Ukraine
I am Pavеl Tоrgаshоv, and I live in Kyiv, Ukraine.
I've been developing software since 1998.
Main activities: processing of large volumes of data, statistics, computer vision and graphics.

My contact email is p_torgashov[at]ukr.net
Follow on   LinkedIn

Comments and Discussions

 
QuestionMissing functionality [modified] Pin
djmarcus19-Oct-14 14:30
memberdjmarcus19-Oct-14 14:30 
AnswerRe: Missing functionality Pin
Pavel Torgashov19-Oct-14 22:34
mvpPavel Torgashov19-Oct-14 22:34 
GeneralRe: Missing functionality Pin
djmarcus20-Oct-14 3:47
memberdjmarcus20-Oct-14 3:47 
GeneralRe: Missing functionality Pin
Pavel Torgashov20-Oct-14 9:02
mvpPavel Torgashov20-Oct-14 9:02 
QuestionHow to load list using BindingSource? Pin
jdebabrata12-Oct-14 11:20
memberjdebabrata12-Oct-14 11:20 
AnswerRe: How to load list using BindingSource? Pin
Pavel Torgashov12-Oct-14 11:29
mvpPavel Torgashov12-Oct-14 11:29 
QuestionVery useful!!! Pin
Cheung Tat Ming12-Oct-14 7:39
memberCheung Tat Ming12-Oct-14 7:39 
AnswerRe: Very useful!!! Pin
Pavel Torgashov12-Oct-14 8:09
mvpPavel Torgashov12-Oct-14 8:09 
QuestionGood stuff Pavel! Pin
Volynsky Alex6-Oct-14 11:34
professionalVolynsky Alex6-Oct-14 11:34 
GeneralFastTree HScroll Pin
Hermann Jung22-Sep-14 7:24
memberHermann Jung22-Sep-14 7:24 
GeneralRe: FastTree HScroll Pin
Pavel Torgashov22-Sep-14 14:46
mvpPavel Torgashov22-Sep-14 14:46 
GeneralRe: FastTree HScroll Pin
Pavel Torgashov23-Sep-14 2:25
mvpPavel Torgashov23-Sep-14 2:25 
QuestionComparative characteristics? Pin
Member 45586621-Sep-14 7:48
memberMember 45586621-Sep-14 7:48 
AnswerRe: Comparative characteristics? [modified] Pin
Pavel Torgashov21-Sep-14 11:06
mvpPavel Torgashov21-Sep-14 11:06 
Questionarchitecture improvement Pin
Thornik19-Sep-14 10:57
memberThornik19-Sep-14 10:57 
AnswerRe: architecture improvement Pin
Thornik19-Sep-14 11:03
memberThornik19-Sep-14 11:03 
AnswerRe: architecture improvement Pin
Pavel Torgashov19-Sep-14 23:00
mvpPavel Torgashov19-Sep-14 23:00 
GeneralRe: architecture improvement Pin
Thornik20-Sep-14 4:43
memberThornik20-Sep-14 4:43 
GeneralRe: architecture improvement Pin
Pavel Torgashov20-Sep-14 8:53
mvpPavel Torgashov20-Sep-14 8:53 
GeneralRe: architecture improvement Pin
CeGu24-Sep-14 19:42
memberCeGu24-Sep-14 19:42 
GeneralRe: architecture improvement Pin
Thornik25-Sep-14 3:56
memberThornik25-Sep-14 3:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150520.1 | Last Updated 6 Oct 2014
Article Copyright 2014 by Pavel Torgashov
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid