Logo

dev-resources.site

for different kinds of informations.

Navigate PDF Annotations in a TreeView Using WPF PDF Viewer

Published at
5/10/2024
Categories
wpf
syncfusion
ui
desktop
Author
jollenmoyani
Categories
4 categories in total
wpf
open
syncfusion
open
ui
open
desktop
open
Author
12 person written this
jollenmoyani
open
Navigate PDF Annotations in a TreeView Using WPF PDF Viewer

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 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 control.

Let’s get started!

Create a WPF application and add dependencies

First, create a new WPF application and install the following NuGet packages in it:

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.

Refer to the following code example.

<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>
Enter fullscreen mode Exit fullscreen mode

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.

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));
}
Enter fullscreen mode Exit fullscreen mode

After loading the document information in the DocumentLoaded event, add the supported annotation details with the respective page in the TreeView.

Refer to the following code example.

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);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

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;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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 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.

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

Refer to the following image.

Viewing annotations in a tree view and navigating to them using Syncfusion WPF PDF Viewer

Viewing annotations in a tree view and navigating to them using Syncfusion WPF PDF Viewer

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.

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 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 page. If you are new, try our 30-day free trial to explore our incredible features.

If you require assistance, please don’t hesitate to contact us via our support forums, support portal, or feedback portal. We are always eager to help you!

Related blogs

wpf Article's
30 articles in total
Favicon
[WPF] Draw Tree Topology
Favicon
What’s New in WPF Diagram: 2024 Volume 4
Favicon
Implementing Full Transparency No Frame and Acrylic Effects in Avalonia UI
Favicon
𝗚𝗲𝘁 𝗗𝗲𝘃𝗘𝘅𝗽𝗿𝗲𝘀𝘀 .𝗡𝗘𝗧 𝗠𝗔𝗨𝗜 𝗖𝗼𝗻𝘁𝗿𝗼𝗹𝘀 𝗳𝗼𝗿 𝗙𝗿𝗲𝗲 𝗕𝗲𝗳𝗼𝗿𝗲 𝗗𝗲𝗰𝗲𝗺𝗯𝗲𝗿 𝟯𝟭, 𝟮𝟬𝟮𝟰!
Favicon
Por onde anda o WPF?
Favicon
Streamlining .NET Development with Practical Aspects
Favicon
Creating a Dynamic WPF Chart Dashboard to Showcase 2024 Women’s T20 World Cup Statistics
Favicon
In-Depth Technical Analysis of XAML-Based Frameworks and Cross-Platform Project Architecture Design
Favicon
Semantic Searching using Embedding in WPF DataGrid
Favicon
Integrating AI-Powered Smart Location Search in WPF Maps
Favicon
Create a WPF Multi-Bar Chart to Visualize U.S. vs. China Superpower Status
Favicon
AI-Powered Smart Paste in WPF Text Input Layout for Effortless Data Entry
Favicon
Latest LightningChart .NET Release: v.12.1.1 is out now!
Favicon
Create a WPF FastLine Chart to Analyze Global Population Trends by Age Group
Favicon
Introducing AI-Powered Smart Components & Features in Syncfusion Desktop Platforms
Favicon
Chart of the Week: Clean and Preprocess E-Commerce Website Traffic Data Using an AI-Powered Smart WPF Chart
Favicon
Everything You Need to Know About WPF Gantt Control
Favicon
Chart of the Week: Creating a WPF Chart Dashboard to Analyze 2024 T20 World Cup Statistics
Favicon
What’s New in WPF Gantt Chart: 2024 Volume 2
Favicon
Chart of the Week: Creating a WPF Doughnut Chart to Visualize the New European Parliament’s Composition in 2024
Favicon
Chart of the Week: Creating a WPF Pie Chart to Visualize the Percentage of Global Forest Area for Each Country
Favicon
Chart of the Week: Creating a WPF Range Bar Chart to Visualize the Hearing Range of Living Beings
Favicon
Chart of the Week: Creating a WPF Sunburst Chart to Visualize the Syncfusion Chart of the Week Blog Series
Favicon
Chart of the Week: Creating a WPF Stacked Area Chart to Visualize Wealth Distribution in the U.S.
Favicon
Elevating Automation: Mastering PowerShell and C# Integration with Dynamic Paths and Parameters
Favicon
Navigate PDF Annotations in a TreeView Using WPF PDF Viewer
Favicon
Chart of the week: Creating a WPF 3D Column Chart to Visualize the Panama Canal’s Shipment Transit Data
Favicon
Improve Real-Time WPF Visualization of ECG Signals With SciChart
Favicon
Race Strategy Analysis using SciChart WPF
Favicon
Chart of the Week: Creating a WPF Chart Dashboard to Visualize the 2023 World Billionaires List

Featured ones: