windowsforms-400723-controls-and-libraries-tree-list-feature-center-focus-selection-and-navigation-scrollbar-annotations.md
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.
Run Demo: 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;
' 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.
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);
}
Private Sub treeList1_CustomScrollAnnotation(ByVal sender As Object, ByVal e As TreeListCustomScrollAnnotationsEventArgs) _
Handles treeList1.CustomScrollAnnotation
Dim node As TreeListNode = treeList1.FindNodeByFieldValue("DEPARTMENT", "Finance")
e.Annotations = New List(Of TreeListScrollAnnotationInfo)()
Dim info As New TreeListScrollAnnotationInfo() With {
.Node = node,
.Color = Color.Orange
}
e.Annotations.Add(info)
End Sub
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);
}
Private Sub treeList1_CustomScrollAnnotation(ByVal sender As Object, ByVal e As TreeListCustomScrollAnnotationsEventArgs) _
Handles treeList1.CustomScrollAnnotation
Dim node As TreeListNode = treeList1.FindNodeByFieldValue("DEPARTMENT", "Finance")
e.SetAnnotations(Color.Red, node)
End Sub
To implement user-defined bookmarks:
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;
}
Imports DevExpress.Utils
Imports DevExpress.XtraEditors.Annotations
Imports DevExpress.XtraTreeList.Menu
Imports DevExpress.XtraTreeList.Nodes
Imports DevExpress.XtraTreeList.Painter
Private ReadOnly bookmarks As New HashSet(Of Integer)() From {5, 17, 74}
' Set custom annotations.
Private Sub OnCustomScrollAnnotation(ByVal sender As Object, ByVal e As TreeListCustomScrollAnnotationsEventArgs) Handles treeList1.CustomScrollAnnotation
Dim rowHandles() As TreeListNode = bookmarks.Select(Function(x) treeList1.FindNodeByID(x)).ToArray()
e.SetAnnotations(DevExpress.LookAndFeel.DXSkinColors.IconColors.Blue, rowHandles)
End Sub
' Draw a bookmark glyph.
Private Sub OnCustomDrawRowIndicator(ByVal sender As Object, ByVal e As CustomDrawNodeIndicatorEventArgs) Handles treeList1.CustomDrawNodeIndicator
If e.Node Is Nothing OrElse treeList1.IsAutoFilterNode(e.Node) Then
Return
End If
If e.Info.ImageIndex = TreeListPainter.ErrorInNodeIndicatorImageIndex OrElse e.Info.ImageIndex = TreeListPainter.ErrorInFocusedNodeIndicatorImageIndex Then
e.Info.ImageIndex = -1
End If
If (Not ucScrollAnnotationsOptions.BookmarksEnabled) OrElse (Not bookmarks.Contains(e.Node.Id)) Then
Return
End If
e.DefaultDraw()
Dim bookmarkImage = svgImageCollection.GetImage("bookmark", GetPalette(), ScaleDPI.ScaleSize(New Size(8, 8)))
Dim imageBounds = PlacementHelper.Arrange(bookmarkImage.Size, e.Bounds, ContentAlignment.MiddleLeft)
e.Cache.DrawImageUnscaled(bookmarkImage, imageBounds)
e.Handled = True
End Sub
Private Function GetPalette() As Utils.Design.ISvgPaletteProvider
Return Utils.Svg.SvgPaletteHelper.GetSvgPalette(treeList1.LookAndFeel, Utils.Drawing.ObjectState.Normal)
End Function
Private Sub OnScrollAnnotationsStyle(ByVal sender As Object, ByVal e As TreeListScrollAnnotationsStyleEventArgs) Handles treeList1.ScrollAnnotationsStyle
Dim styleColor = ucScrollAnnotationsOptions.GetColor(e.Kind)
If Not styleColor.IsEmpty Then
e.Color = styleColor
End If
End Sub
' Implement forward and back navigation.
Private Overloads Sub OnKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles treeList1.KeyDown
If e.KeyData = (Keys.F2 Or Keys.Control) OrElse e.KeyData = (Keys.B Or Keys.Control) Then
e.Handled = ToggleBookmark(treeList1.FocusedNode)
End If
If e.KeyData = Keys.F2 Then
e.Handled = treeList1.MoveToNextScrollAnnotation(ScrollAnnotationKind.Custom)
End If
If e.KeyData = (Keys.F2 Or Keys.Shift) Then
e.Handled = treeList1.MoveToPrevScrollAnnotation(ScrollAnnotationKind.Custom)
End If
End Sub
Private Function ToggleBookmark(ByVal node As TreeListNode) As Boolean
Dim dataIndex As Integer = If(node IsNot Nothing, node.Id, -1)
If dataIndex < 0 Then
Return False
End If
If bookmarks.Contains(dataIndex) Then
bookmarks.Remove(dataIndex)
Else
bookmarks.Add(dataIndex)
End If
treeList1.RefreshScrollAnnotations(ScrollAnnotationKind.Custom)
treeList1.InvalidateNode(node)
Return True
End Function
TreeList control does not auto-hide them. See the following help topic for more information: WindowsFormsSettings.ScrollUIMode.See Also