Skip to main content

Scrollbar Annotations

  • 5 minutes to read

Scrollbar annotations help users locate specific nodes—such as those with validation errors, focus, or selection. The TreeList displays annotations as colored markers on the vertical scrollbar to visualize positions of corresponding nodes.

Scrollbar Annotations - WinForms TreeList, DevExpress

Run Demo: Scrollbar Annotations

Enable Scrollbar Annotations

Use the OptionsScrollAnnotations property to enable specific annotations:

  • ShowErrors - marks nodes with validation errors.
  • ShowFocusedRow - marks the focused node.
  • ShowSelectedRows - marks selected nodes.
  • ShowCustomAnnotations - marks nodes with custom annotations supplied via the CustomScrollAnnotation event.
// Enable annotations for the focused row.
treeList.OptionsScrollAnnotations.ShowFocusedRow = DefaultBoolean.True;

Note

The TreeList control also displays scrollbar annotations for search requests if the Find Panel operates in search mode.

Custom Annotations

Handle the CustomScrollAnnotation event to supply custom annotation data. Use the TreeListScrollAnnotationInfo class to specify annotation properties:

  • Node - the associated TreeList node.
  • Color - the color of the annotation.

Add annotation objects to the e.Annotations collection:

using DevExpress.XtraTreeList;

void treeList1_CustomScrollAnnotation(object sender, 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);
}

Use the e.SetAnnotations method to apply annotations to a specific node. This method resets previous annotations.

using DevExpress.XtraTreeList;

void treeList1_CustomScrollAnnotation(object sender, TreeListCustomScrollAnnotationsEventArgs e) {
    TreeListNode node = treeList1.FindNodeByFieldValue("DEPARTMENT", "Finance");
    e.SetAnnotations(Color.Red, node);
}

Bookmarks with Scrollbar Annotations and Node Indicators

To implement user-defined bookmarks:

  1. Handle the TreeList.CustomScrollAnnotation event to associate nodes with annotations.
  2. Handle the TreeList.CustomDrawNodeIndicator event to draw bookmark glyphs.
  3. Handle the TreeList.ScrollAnnotationsStyle event to customize annotation appearance.
  4. Handle the KeyDown event to navigate between annotated nodes using 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;
}

Specific Notes

See Also