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 the following goals:
- The control must be able to display big data set. By design, no less than 1mln items – without lags.
- 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.
- The control must implement virtual mode and not take large amount of memory.
- The control must be flexible and allow to be easy extending and inheriting.
- 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.).
- Multiselection, checkboxes, icons.
- Wide set of customizing: coloring, custom height of items, custom item drawing, intending, visibility.
- 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). It receives all data 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];
}
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 modes 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 an instance of any type, or even null
. But in future, in event handlers, you must return children or text for given object.
Next, there are 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:\")
...
private void ft_NodeChildrenNeeded(object sender, NodeChildrenNeededEventArgs e)
{
var path = e.Node as string;
e.Children = Directory.GetDirectories(path);
}
private void ft_NodeTextNeeded(object sender, FastTreeNS.StringNodeEventArgs e)
{
var path = e.Node as string;
e.Result = Path.GetDirectoryName(path);
}
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 modes 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
– return 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
– inform that node/items state was changed.
Events NodeDrag
, DragOverNode
, DropOverNode
, ItemDrag
, ItemOverItem
, ItemDropOverItem
– these events occur when user starts 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.
Property 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)
– rebuilds 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
- 18th September, 2014 - First release
- 20th September, 2014 - Virtual
checkbox
es mode was added. Samples FastListVirtualCheckboxesSample
and FastTreeDragAndDropSample
were added. - 23rd September, 2014 - Memory usage was improved, stress tests were added.
- 6th October, 2014 -
HotTracking
and AllowSelectItems
properties were added