Scrollbar Annotations
- 5 minutes to read
When tree lists contain many nodes, locating those with validation errors and those that are focused or selected can be difficult. To help locate these nodes expeditiously, display scrollbar annotations. The latter are colored marks on the vertical scrollbar that reflect the location of corresponding nodes in the tree list.
How to Enable
Use the OptionsScrollAnnotations property to access options that allow you to enable/disable specific annotations:
- ShowErrors — specifies whether to mark nodes with validation errors
- ShowFocusedRow — specifies whether to mark the focused node
- ShowSelectedRows — specifies whether to mark selected nodes
- ShowCustomAnnotations — specifies whether to mark nodes with custom annotations provided using a dedicated event (see below)
Scrollbar annotations are disabled if an option equals Default. Set the option to True to enable them.
// Enable annotations for the focused row.
treeList.OptionsScrollAnnotations.ShowFocusedRow = DefaultBoolean.True;
Tree list also displays scrollbar annotations for search requests if the Find Panel is in search mode.
Limitations
Scrollbar annotations have the following limitations.
- Tree list lookup editor does not support scrollbar annotations for search requests in the Find Panel.
- Scrollbar annotations for selected nodes are only supported in multiple node selection mode.
Custom Annotations
The CustomScrollAnnotation event allows you to provide data about custom annotations. Data is represented by the TreeListScrollAnnotationInfo type, which exposes the following properties.
- Node — the node for which to show a scroll annotation
- Color — color of the annotation
When handling this event, create data objects and add them to the Annotations collection in the event arguments.
private void treeList1_CustomScrollAnnotation(object sender, DevExpress.XtraTreeList.TreeListCustomScrollAnnotationsEventArgs e) {
TreeListNode node = treeList1.FindNodeByFieldValue("DEPARTMENT", "Finance");
e.Annotations = new List<TreeListScrollAnnotationInfo>();
TreeListScrollAnnotationInfo info = new TreeListScrollAnnotationInfo() {
Node = node,
Color = Color.Orange
};
e.Annotations.Add(info);
}
The SetAnnotations method allows you to set annotations for a node array. Note that this method does not add annotations, but resets them.
private void treeList1_CustomScrollAnnotation(object sender, DevExpress.XtraTreeList.TreeListCustomScrollAnnotationsEventArgs e) {
TreeListNode node = treeList1.FindNodeByFieldValue("DEPARTMENT", "Finance");
e.SetAnnotations(Color.Red, node);
}
How to Create Row Bookmarks Using Scrollbar Annotations and Node Indicators
Note
Run the Scrollbar Annotations & Bookmarks demo to see the functionality in action.
You can provide users with the ability to bookmark nodes and navigate between them using the keyboard. To implement this functionality, handle the following events.
- The TreeList.CustomScrollAnnotation event — to associate nodes with custom annotations.
- The TreeList.CustomDrawNodeIndicator event — to draw a bookmark glyph against each annotated node.
- The TreeList.ScrollAnnotationsStyle event — to customize the scrollbar annotation color and alignment.
- The Control.KeyDown event — to implement forward and back navigation between annotated nodes. To scroll the tree list in code, use the TreeList.MoveToNextScrollAnnotation and TreeList.MoveToPrevScrollAnnotation methods.
using DevExpress.Utils;
using DevExpress.XtraEditors.Annotations;
using DevExpress.XtraTreeList.Menu;
using DevExpress.XtraTreeList.Nodes;
using DevExpress.XtraTreeList.Painter;
treeList1.CustomScrollAnnotation += OnCustomScrollAnnotation;
treeList1.CustomDrawNodeIndicator += OnCustomDrawRowIndicator;
treeList1.ScrollAnnotationsStyle += OnScrollAnnotationsStyle;
treeList1.KeyDown += OnKeyDown;
readonly HashSet<int> bookmarks = new HashSet<int>() { 5, 17, 74 };
// Set custom annotations.
void OnCustomScrollAnnotation(object sender, TreeListCustomScrollAnnotationsEventArgs e) {
TreeListNode[] rowHandles = bookmarks.Select(x => treeList1.FindNodeByID(x)).ToArray();
e.SetAnnotations(DevExpress.LookAndFeel.DXSkinColors.IconColors.Blue, rowHandles);
}
Utils.Design.ISvgPaletteProvider GetPalette() {
return Utils.Svg.SvgPaletteHelper.GetSvgPalette(treeList1.LookAndFeel, Utils.Drawing.ObjectState.Normal);
}
void OnScrollAnnotationsStyle(object sender, TreeListScrollAnnotationsStyleEventArgs e) {
var styleColor = ucScrollAnnotationsOptions.GetColor(e.Kind);
if(!styleColor.IsEmpty)
e.Color = styleColor;
}
// Draw a bookmark glyph.
void OnCustomDrawRowIndicator(object sender, CustomDrawNodeIndicatorEventArgs e) {
if(e.Node == null || treeList1.IsAutoFilterNode(e.Node))
return;
if(e.Info.ImageIndex == TreeListPainter.ErrorInNodeIndicatorImageIndex ||
e.Info.ImageIndex == TreeListPainter.ErrorInFocusedNodeIndicatorImageIndex) {
e.Info.ImageIndex = -1;
}
if(!ucScrollAnnotationsOptions.BookmarksEnabled || !bookmarks.Contains(e.Node.Id))
return;
e.DefaultDraw();
var bookmarkImage = svgImageCollection.GetImage("bookmark", GetPalette(), ScaleDPI.ScaleSize(new Size(8, 8)));
var imageBounds = PlacementHelper.Arrange(bookmarkImage.Size, e.Bounds, ContentAlignment.MiddleLeft);
e.Cache.DrawImageUnscaled(bookmarkImage, imageBounds);
e.Handled = true;
}
// Implement forward and back navigation.
void OnKeyDown(object sender, KeyEventArgs e) {
if(e.KeyData == (Keys.F2 | Keys.Control) || e.KeyData == (Keys.B | Keys.Control))
e.Handled = ToggleBookmark(treeList1.FocusedNode);
if(e.KeyData == Keys.F2)
e.Handled = treeList1.MoveToNextScrollAnnotation(ScrollAnnotationKind.Custom);
if(e.KeyData == (Keys.F2 | Keys.Shift))
e.Handled = treeList1.MoveToPrevScrollAnnotation(ScrollAnnotationKind.Custom);
}
bool ToggleBookmark(TreeListNode node) {
int dataIndex = node != null ? node.Id : -1;
if(dataIndex < 0)
return false;
if(bookmarks.Contains(dataIndex))
bookmarks.Remove(dataIndex);
else
bookmarks.Add(dataIndex);
treeList1.RefreshScrollAnnotations(ScrollAnnotationKind.Custom);
treeList1.InvalidateNode(node);
return true;
}