Navigate PDF Annotations in a TreeView Using WPF PDF Viewer
Tags: wpf, syncfusion, ui, desktop
Published: 2024-05-10 04:15:27

---
title: Navigate PDF Annotations in a TreeView Using WPF PDF Viewer
published: true
date: 2024-05-09 11:00:52 UTC
tags: wpf, syncfusion, ui, desktop
canonical_url: https://www.syncfusion.com/blogs/post/navigate-pdf-annotations-treeview-wpf-pdf-viewer
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34td07q9pyprs3ezgagp.png
---
**TL;DR:** Annotations in PDFs are like digital sticky notes, helpful for comments and information. This blog discusses organizing them effectively using a tree view grouped by pages, making navigation smooth with Syncfusion WPF PDF Viewer.

[Annotations](https://en.wikipedia.org/wiki/Annotation "Wikipedia Link: Annotation") are invaluable tools for adding comments, notes, and other relevant information to PDF documents. When managing these annotations, organizing them in a structured manner can significantly enhance navigation and usability. 

In this blog, we’ll explore how to efficiently showcase PDF annotations in a tree view, grouped by the pages they belong to, and seamlessly navigate through them using the Syncfusion [WPF PDF Viewer](https://www.syncfusion.com/wpf-controls/pdf-viewer "WPF PDF Viewer control") control.

Let’s get started!

## Create a WPF application and add dependencies

First, create a new [WPF application ](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/get-started/create-app-visual-studio?view=netdesktop-7.0 "Create a new WPF app with .NET")and install the following NuGet packages in it:

- [Syncfusion.PdfViewer.WPF](https://www.nuget.org/packages/Syncfusion.PdfViewer.WPF "Syncfusion.PdfViewer.WPF NuGet package")
- [Syncfusion.SfSkinManager.WPF](https://www.nuget.org/packages/Syncfusion.SfSkinManager.WPF "Syncfusion.SfSkinManager.WPF NuGet package")
- [Syncfusion.Themes.FluentLight.WPF](https://www.nuget.org/packages/Syncfusion.Themes.FluentLight.WPF "Syncfusion.Themes.FluentLight.WPF NuGet package")

## Organize PDF Viewer and TreeView

Let’s create a main content page in the **MainWindow.xaml** file and add the Syncfusion WPF PDF Viewer and WPF Framework’s TreeView as the children to it. Then, add the event handler for the TreeView’s [SelectedItemChanged event](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.treeview.selecteditemchanged?view=windowsdesktop-7.0 "API reference: SelectedItemChanged Event").

Refer to the following code example.

```xml
<Window
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       xmlns:local="clr-namespace:WPF_PDFViewer_Annotations"
       xmlns:PdfViewer="clr-namespace:Syncfusion.Windows.PdfViewer;assembly=Syncfusion.PdfViewer.WPF" xmlns:syncfusion="http://schemas.syncfusion.com/wpf" x:Class="WPF_PDFViewer_Annotations.MainWindow"
       mc:Ignorable="d"
       Title="MainWindow" Height="450" Width="800" WindowState="Maximized">
 <Grid>
  <Grid.ColumnDefinitions>
   <ColumnDefinition Width="*"/>
   <ColumnDefinition Width="250"/>
  </Grid.ColumnDefinitions>
  <PdfViewer:PdfViewerControl x:Name="pdfViewer"/>
  <TreeView x:Name="treeView" Grid.Column="1" SelectedItemChanged="treeView_SelectedItemChanged"/>
 </Grid>
</Window>
```

In the **MainWindow.xaml.cs** file, let’s set the theme for Syncfusion WPF PDF Viewer control and trigger the **DocumentLoaded** event with the **AnnotationChanged** event for all supported annotations.

Refer to the following code example.

```csharp
public MainWindow()
{
    SfSkinManager.SetTheme(this, new Theme("FluentLight"));
    InitializeComponent();
    pdfViewer.DocumentLoaded += PdfViewer_DocumentLoaded;
    pdfViewer.FreeTextAnnotationChanged += PdfViewer_FreeTextAnnotationChanged;
    pdfViewer.StickyNoteAnnotationChanged += PdfViewer_StickyNoteAnnotationChanged;
    pdfViewer.InkAnnotationChanged += PdfViewer_InkAnnotationChanged;
    pdfViewer.TextMarkupAnnotationChanged += PdfViewer_TextMarkupAnnotationChanged;
    pdfViewer.ShapeAnnotationChanged += PdfViewer_ShapeAnnotationChanged;
    pdfViewer.StampAnnotationChanged += PdfViewer_StampAnnotationChanged;
    pdfViewer.Load("../../Data/Sample Document.pdf");
    treeView.Background = new SolidColorBrush(Color.FromRgb(235,235,238));
}
```

After loading the document information in the [DocumentLoaded](https://help.syncfusion.com/cr/wpf/Syncfusion.Windows.PdfViewer.PdfViewerControl.html#Syncfusion_Windows_PdfViewer_PdfViewerControl_DocumentLoaded "API reference: DocumentLoaded Property for the WPF PDF Viewer") event, add the supported annotation details with the respective page in the TreeView.

Refer to the following code example.

```csharp
private void PdfViewer_DocumentLoaded(object sender, EventArgs args)
{
    PdfLoadedDocument loadedDocument = pdfViewer.LoadedDocument;
    treeView.Items.Clear();
    for (int i = 0; i < loadedDocument.Pages.Count; i++)
    {
        TreeViewItem viewItem = new TreeViewItem();
        if (loadedDocument.Pages[i].Annotations.Count > 0)
        {
            viewItem.Header = "PAGE - " + (i + 1);
            viewItem.FontSize = 16;
            treeView.Items.Add(viewItem);
            viewItem.IsExpanded = true;
            for (int j = 0; j < loadedDocument.Pages[i].Annotations.Count; j++)
            {
                PdfLoadedAnnotation annotation = loadedDocument.Pages[i].Annotations[j] as PdfLoadedAnnotation;
                if (annotation is PdfLoadedInkAnnotation || annotation is PdfLoadedTextMarkupAnnotation || annotation is PdfLoadedEllipseAnnotation
                    || annotation is PdfLoadedLineAnnotation || annotation is PdfLoadedRectangleAnnotation || annotation is PdfLoadedSquareAnnotation
                    || annotation is PdfLoadedCircleAnnotation || annotation is PdfLoadedFreeTextAnnotation || annotation is PdfLoadedRubberStampAnnotation
                    || annotation is PdfLoadedPopupAnnotation || annotation is PdfLoadedPolygonAnnotation || annotation is PdfLoadedPolyLineAnnotation)
                {
                    string name = annotation.ToString();
                    string[] annotNames = name.Split('.');
                    TreeViewItem childItem = new TreeViewItem();
                    childItem.Header = annotation.Type.ToString();
                    childItem.Tag = annotation;
                    viewItem.Items.Add(childItem);
                }
            }
            if (viewItem.Items.Count == 0)
                treeView.Items.Remove(viewItem);
        }
    }
}
```

While adding/removing the annotations, we need to update the respective annotation data in the treeview. To do so, we will use the **AnnotationChanged** event to update the treeview values.

Refer to the following code example.

```csharp
private void PdfViewer_InkAnnotationChanged(object sender, InkAnnotationChangedEventArgs e)
{
    PerformAddorRemoveAnnotations("InkAnnotation",e.Name,e.Action,e.PageNumber);
}

private void PerformAddorRemoveAnnotations(string name ,string annotationName ,AnnotationChangedAction action ,int annotationPageNumber)
{
    if (action == AnnotationChangedAction.Add)
    {
        PdfLoadedDocument lDoc = pdfViewer.LoadedDocument;
        if (treeView.Items.Count > 0)
        {
            for (int i = 0; i < treeView.Items.Count; i++)
            {
                string[] page = (treeView.Items[i] as TreeViewItem).Header.ToString().Split(' ');
                int pageNumber = int.Parse(page[page.Length - 1]);
                if (pageNumber == annotationPageNumber)
                {
                    TreeViewItem item = treeView.Items[i] as TreeViewItem;
                    TreeViewItem childItem = new TreeViewItem();
                    for (int j = 0; j < lDoc.Pages[annotationPageNumber - 1].Annotations.Count; j++)
                    {
                        if (lDoc.Pages[annotationPageNumber - 1].Annotations[j].Name == annotationName)
                        {
                            childItem.Header = name;
                            childItem.Tag = lDoc.Pages[annotationPageNumber - 1].Annotations[j];
                            break;
                        }
                    }
                    item.Items.Add(childItem);
                    break;
                }
                else if (pageNumber > annotationPageNumber)
                {
                    TreeViewItem item = new TreeViewItem();
                    item.Header = "PAGE - " + annotationPageNumber;
                    treeView.Items.Insert(i, item);
                    TreeViewItem childItem = new TreeViewItem();
                    for (int j = 0; j < lDoc.Pages[annotationPageNumber - 1].Annotations.Count; j++)
                    {
                        if (lDoc.Pages[annotationPageNumber - 1].Annotations[j].Name == annotationName)
                        {
                            childItem.Header = name;
                            childItem.Tag = lDoc.Pages[annotationPageNumber - 1].Annotations[j];
                            break;
                        }
                    }
                    item.Items.Add(childItem);
                }
            }
        }
        else
        {
            TreeViewItem item = new TreeViewItem();
            item.Header = "PAGE - " + annotationPageNumber;
            item.FontSize = 16;
            treeView.Items.Add(item);
            TreeViewItem childItem = new TreeViewItem();
            for (int j = 0; j < lDoc.Pages[annotationPageNumber - 1].Annotations.Count; j++)
            {
                if (lDoc.Pages[annotationPageNumber - 1].Annotations[j].Name == annotationName)
                {
                    childItem.Header = name;
                    childItem.Tag = lDoc.Pages[annotationPageNumber - 1].Annotations[j];
                    break;
                }
            }
            item.Items.Add(childItem);
        }
    }
    else if (action == AnnotationChangedAction.Remove)
    {
        for (int i = 0; i < treeView.Items.Count; i++)
        {
            string[] page = (treeView.Items[i] as TreeViewItem).Header.ToString().Split(' ');
            int pageNumber = int.Parse(page[page.Length - 1]);
            if (pageNumber == annotationPageNumber)
            {
                TreeViewItem item = treeView.Items[i] as TreeViewItem;
                for (int j = 0; j < item.Items.Count; j++)
                {
                    PdfLoadedAnnotation loadedAnnotation = (item.Items[j] as TreeViewItem).Tag as PdfLoadedAnnotation;
                    PdfAnnotation annotation = (item.Items[j] as TreeViewItem).Tag as PdfAnnotation;
                    if (loadedAnnotation != null)
                    {
                        if (annotationName == loadedAnnotation.Name)
                        {
                            item.Items.RemoveAt(j);
                            break;
                        }
                    }
                    else if (annotation != null)
                    {
                        if (annotationName == annotation.Name)
                        {
                            item.Items.RemoveAt(j);
                            break;
                        }
                    }
                }
                if (item.Items.Count == 0)
                {
                    treeView.Items.RemoveAt(i);
                }
                break;
            }
        }
    }
}
```

## Implement navigation on annotation selection

Next, we will implement the code to select an annotation in the treeview that will navigate you to its corresponding annotation position in the PDF. PDF Viewer provides support to select and bring an annotation to view programmatically using the overload [SelectAnnotation](https://help.syncfusion.com/cr/wpf/Syncfusion.Windows.PdfViewer.PdfViewerControl.html#Syncfusion_Windows_PdfViewer_PdfViewerControl_SelectAnnotation_System_String_System_Boolean_ "API reference: SelectAnnotation method for the WPF PDF Viewer") method with **BringIntoView** Parameter.

The annotation’s name and true value for **BringIntoView** should be passed as a parameter to select and bring an annotation into view, which should be handled in the **SelectedItemChanged** event of TreeView.

Implement the following code in the **treeView\_SelectedItemChanged** method, which is present in the **MainWindow.xaml.cs** file.

```csharp
private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    var selectedItem = treeView.SelectedItem as TreeViewItem;
    if (selectedItem != null && !selectedItem.Header.ToString().Contains("PAGE"))
    {
        PdfLoadedAnnotation loadedAnnotation = selectedItem.Tag as PdfLoadedAnnotation;
        PdfAnnotation annotation = selectedItem.Tag as PdfAnnotation;
        if (loadedAnnotation != null)
            pdfViewer.SelectAnnotation(loadedAnnotation.Name, true);
        else if (annotation != null)
            pdfViewer.SelectAnnotation(annotation.Name, true);
    }
}
```

Refer to the following image.
<figure>

  <img src="https://www.syncfusion.com/blogs/wp-content/uploads/2024/05/Viewing-annotations-in-a-tree-view-and-navigating-to-them-using-Syncfusion-WPF-PDF-Viewer.gif" alt="Viewing annotations in a tree view and navigating to them using Syncfusion WPF PDF Viewer" style="width:100%">

  <figcaption>Viewing annotations in a tree view and navigating to them using Syncfusion WPF PDF Viewer</figcaption>

</figure>

## GitHub reference

Also, refer to view PDF annotations in the tree view and navigate to them using the Syncfusion WPF PDF Viewer demo on [GitHub](https://github.com/SyncfusionExamples/WPF-PDFViewer-Examples/tree/master/Annotations/List%20Out%20Annotation/WPF_PDFViewer_Annotations "Viewing annotations in a tree view and navigating to them using Syncfusion WPF PDF Viewer on GitHub demo").

## Conclusion

Thanks for reading! In this blog, we have seen how to view annotations in a PDF document using a tree view and easily navigate to them using Syncfusion [WPF PDF Viewer](https://www.syncfusion.com/wpf-controls/pdf-viewer "WPF PDF Viewer control") control.  Try out the steps given in this blog and leave your feedback in the comments section given below.

The existing customers can download the latest version of Essential Studio from the [License and Downloads](https://www.syncfusion.com/account "Essential Studio License and Downloads page") page. If you are new, try our 30-day [free trial](https://www.syncfusion.com/downloads "Get the free evaluation of the Essential Studio products") to explore our incredible features. 

If you require assistance, please don’t hesitate to contact us via our [support forums](https://www.syncfusion.com/forums "Syncfusion Support Forums"), [support portal](https://support.syncfusion.com/ "Syncfusion Support Portal"), or [feedback portal](https://www.syncfusion.com/feedback "Syncfusion Feedback Portal"). We are always eager to help you!

## Related blogs

- [Harmonizing Powerhouses: Syncfusion WPF Controls Are Now Compatible with Avalonia XPF](https://www.syncfusion.com/blogs/post/wpf-ui-compatible-avalonia-xpf "Blog: Harmonizing Powerhouses: Syncfusion WPF Controls Are Now Compatible with Avalonia XPF")
- [Chart of the Week: Creating a WPF 100% Stacked Area Chart to Visualize the World Vehicle Production in Major Countries](https://www.syncfusion.com/blogs/post/wpf-100-stacked-area-chart-vehicle "Blog: Chart of the Week: Creating a WPF 100% Stacked Area Chart to Visualize the World Vehicle Production in Major Countries")
- [Streamline Your WPF Development with Syncfusion: Introducing the WPF Template Studio for Visual Studio](https://www.syncfusion.com/blogs/post/wpf-template-studio-visual-studio "Blog: Streamline Your WPF Development with Syncfusion: Introducing the WPF Template Studio for Visual Studio")
- [Visualize JSON Data Quickly Using WPF Charts](https://www.syncfusion.com/blogs/post/visualize-json-data-wpf-charts "Blog: Visualize JSON Data Quickly Using WPF Charts")