Easily Lock and Unlock Annotations Using Xamarin.Forms PDF Viewer

Jollen Moyani - Nov 23 '22 - - Dev Community

According to Wikipedia, “An annotation is extra information associated with a particular point in a document.” Annotations can be locked to keep users from editing them. Syncfusion’s Xamarin.Forms PDF Viewer can differentiate between locked and unlocked annotations, and you can use it to lock or unlock them dynamically.

In a previous blog, we learned how to view PDF annotations as a list and navigate through them using our Xamarin PDF Viewer. This article is an extension of that blog. We will now learn how to identify whether an annotation is locked and the procedure to lock or unlock an annotation dynamically.

We will use the same project example we used for showcasing annotations in a list view.

Selection border color to specify locked annotations

We can use the selection border color feature in our Xamarin PDF Viewer to tell the difference between locked and unlocked annotations.

Refer to the following images.

Normal Annotation Locked Annotation
Annotation in normal state Annotations in locked state

The default color for locked annotations’ selection border is gray. You can customize this by setting your required color to the LockedStrokeColor property.

pdfViewerControl.SelectorSettings.LockedStrokeColor = Color.Red;
Enter fullscreen mode Exit fullscreen mode

Specify the locked annotations in a list view

Let’s see how to display the locked annotations in a list view using the Xamarin PDF Viewer.

The IsLocked property in each annotation settings class tells us whether an annotation is in a locked state or not.

Here, we are going to add an image component in the ListViewItem.xaml to specify an annotation’s locked status.

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="AnnotationsListView.ListViewItem">
 <ContentView.Content>
  <StackLayout HeightRequest="40" Orientation="Horizontal">
   <Label x:Name="annotationFontIcon" Margin="10,0,0,0" VerticalOptions="Center" InputTransparent="true" BackgroundColor="Transparent" TextColor="#0076FF" FontSize="16"/>
   <Label x:Name="annotationLabel" FontSize="Medium" TextColor="Black" Padding="10,0,0,0" VerticalOptions="Center"/>
   <Image x:Name="annotationLockedStatus" HorizontalOptions="EndAndExpand" VerticalOptions="Center"
            Margin="0,0,10,0" HeightRequest="28" WidthRequest="28"/>
  </StackLayout>
 </ContentView.Content>
</ContentView>
Enter fullscreen mode Exit fullscreen mode

Then, in the ListViewItem_BindingContextChanged event handler, we implement the logic to identify whether the annotations are locked or not and set the appropriate status image for the image component.

private void ListViewItem_BindingContextChanged(object sender, EventArgs e)
{
  if (BindingContext == null)
  return;

  bool isLocked = false;

  annotationFontIcon.FontFamily = FontMappingHelper.FontFamily;

  if (BindingContext is ShapeAnnotation shape)
  {
    isLocked = shape.Settings.IsLocked;
    annotationLabel.Text = shape.ShapeAnnotationType.ToString();
    if (shape.ShapeAnnotationType == ShapeAnnotationType.Line)
    {
      annotationFontIcon.Text = FontMappingHelper.Line;
    }
    else if (shape.ShapeAnnotationType == ShapeAnnotationType.Rectangle)
    {
      annotationFontIcon.Text = FontMappingHelper.Rectangle;
    }
    else if (shape.ShapeAnnotationType == ShapeAnnotationType.Circle)
    {
      annotationFontIcon.Text = FontMappingHelper.Circle;
    }
    else if (shape.ShapeAnnotationType == ShapeAnnotationType.Arrow)
    {
      annotationFontIcon.Text = FontMappingHelper.Arrow;
    }
    else if (shape.ShapeAnnotationType == ShapeAnnotationType.Polygon)
    {
      annotationFontIcon.Text = FontMappingHelper.Polygon;
    }
  }
  else if (BindingContext is TextMarkupAnnotation textMarkup)
  {
    isLocked = textMarkup.Settings.IsLocked;
    annotationLabel.Text = textMarkup.TextMarkupAnnotationType.ToString();
    if (textMarkup.TextMarkupAnnotationType == TextMarkupAnnotationType.Highlight)
    {
      annotationFontIcon.Text = FontMappingHelper.Highlight;
    }
    else if (textMarkup.TextMarkupAnnotationType == TextMarkupAnnotationType.Strikethrough)
    {
      annotationFontIcon.Text = FontMappingHelper.StrikeThrough;
    }
    else if (textMarkup.TextMarkupAnnotationType == TextMarkupAnnotationType.Underline)
    {
      annotationFontIcon.Text = FontMappingHelper.Underline;
    }
  }
  else if (BindingContext is FreeTextAnnotation freeText)
  {
     isLocked = freeText.Settings.IsLocked;
     annotationLabel.Text = "Free Text";
     annotationFontIcon.Text = FontMappingHelper.EditText;
  }
  else if (BindingContext is InkAnnotation ink)
  {
     isLocked = ink.Settings.IsLocked;
     annotationLabel.Text = "Ink";
     annotationFontIcon.Text = FontMappingHelper.Ink;
  }

  annotationLockedStatus.Source = isLocked ? ImageSource.FromResource("AnnotationsListView.Assets.Locked_Status.png")
  : null;
}
Enter fullscreen mode Exit fullscreen mode

These changes will result in displaying the lock image for the locked annotations next to the annotation names. Refer to the following image.

Displaying Locked Annotations in a List Using the Xamarin.Forms PDF Viewer

Displaying Locked Annotations in a List Using the Xamarin.Forms PDF Viewer

Lock or unlock annotations dynamically

Use the IsLocked property in each annotation settings class to lock or unlock annotations dynamically.

In the following code example, we are going to add a button to the mainContentView grid in the MainPage.xaml file. Then, we implement the logic to lock or unlock the annotations in the button clicked event handler ( lockOrUnlockButton_Clicked ) in the MainPage.xaml.cs file.

To update the locked or unlocked status in the list view dynamically, clear and set the updated Annotations collection to the list view’s ItemsSource property in the hamburgerButton_Clicked event handler.

Refer to the following code examples.

*MainPage.xaml *

<Grid x:Name="mainContentView" BackgroundColor="White">
 <Grid.RowDefinitions>
  <RowDefinition Height="50"/>
  < Height="auto"/>
 </Grid.RowDefinitions>
 <StackLayout BackgroundColor="#1aa1d6" Orientation="Horizontal">
  <Button x:Name="hamburgerButton" HeightRequest="50" WidthRequest="50"
            HorizontalOptions="Center" FontSize="14"
            BackgroundColor="#1aa1d6"
            Clicked="hamburgerButton_Clicked"
            Margin="5,0,0,0"/>
   <Label x:Name="headerLabel" HeightRequest="50" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" Text="Annotations ListView" FontSize="20" TextColor="White" BackgroundColor="#1aa1d6"/>
 </StackLayout>
 <pdfviewer:SfPdfViewer x:Name="pdfViewer" Grid.Row="1" InputFileStream="{Binding PdfDocumentStream}"></pdfviewer:SfPdfViewer>
  <Grid x:Name="lockStatusToolbar" BackgroundColor="#1aa1d6" Grid.Row="2">
   <StackLayout Orientation="Horizontal" HorizontalOptions="Center">
    <Image x:Name="lockOrUnlockImage" HeightRequest="35" WidthRequest="35"></Image>
    <Button x:Name="lockOrUnlockButton" HeightRequest="50"
              TextColor="White"
              HorizontalOptions="Center"
              BackgroundColor="#1aa1d6" FontSize="Medium"
              BindingContext="{x:Reference Name=listView}"
              Clicked="lockOrUnlockButton_Clicked"/>
   </StackLayout>
 </Grid>
</Grid>
Enter fullscreen mode Exit fullscreen mode

*MainPage.xaml.cs *

private void hamburgerButton_Clicked(object sender, EventArgs e)
{
  if (listView.ItemsSource != null)
  listView.ItemsSource = null;

  listView.DataSource.GroupDescriptors.Add(new GroupDescriptor()
  {
    PropertyName = "PageNumber",
    KeySelector = (object obj) =>
    {
      var item = (obj as IAnnotation);
      return "PAGE " + item.PageNumber;
    },
  });
  listView.ItemsSource = pdfViewer.Annotations;
  navigationDrawer.ToggleDrawer();
}
Enter fullscreen mode Exit fullscreen mode

#region Lock Or Unlock Annotations

private void lockOrUnlockButton_Clicked(object sender, EventArgs e)
{
  DetermineLockStatus(pdfViewer.SelectedAnnotation, true);
}

/// <summary>
/// Determines the annotation's locked status and changes its status from locked to unlocked and vice versa.
/// </summary>
/// <param name="annotation">Selected annotation</param>
/// <param name="changeLockStatus">Indicates whether the annotation's locked status has to be changed or not</param>
private void DetermineLockStatus(IAnnotation annotation, bool changeLockStatus)
{
  bool isLocked = false;

  if (annotation is ShapeAnnotation shape)
  {
    isLocked = shape.Settings.IsLocked;
    if (changeLockStatus)
    {
      isLocked = shape.Settings.IsLocked = shape.Settings.IsLocked ? false : true;
    }
  }
  else if (annotation is TextMarkupAnnotation textMarkup)
  {
    isLocked = textMarkup.Settings.IsLocked;
    if (changeLockStatus)
    {
      isLocked = textMarkup.Settings.IsLocked = textMarkup.Settings.IsLocked ? false : true;
    }
  }
  else if (annotation is FreeTextAnnotation freeText)
  {
    isLocked = freeText.Settings.IsLocked;
    if (changeLockStatus)
    {
      isLocked = freeText.Settings.IsLocked = freeText.Settings.IsLocked ? false : true;
    }
  }
  else if (annotation is InkAnnotation ink)
  {
    isLocked = ink.Settings.IsLocked;
    if (changeLockStatus)
    {
      isLocked = ink.Settings.IsLocked = ink.Settings.IsLocked ? false : true;
    }
  }

  lockOrUnlockImage.Source = isLocked ? ImageSource.FromResource("AnnotationsListView.Assets.Locked.png")
    : ImageSource.FromResource("AnnotationsListView.Assets.Unlocked.png");
  lockOrUnlockButton.Text = isLocked ? "UNLOCK" : "LOCK";
}
#endregion
Enter fullscreen mode Exit fullscreen mode

These changes will result in displaying the lock status toolbar with the lock or unlock button at the bottom of the page, which can be used to lock or unlock annotations. Refer to the following GIF image.

Dynamically Locking and Unlocking Annotations Using Xamarin.Forms PDF Viewer

Dynamically Locking and Unlocking Annotations Using Xamarin.Forms PDF Viewer

Note: To learn more about the functionalities supported in the Xamarin.Forms PDF Viewer, refer to the getting started documentation.

GitHub reference

For more details, check out the complete code example on locking and unlocking annotations using Syncfusion’s Xamarin.Forms PDF Viewer on GitHub.

Conclusion

Thanks for reading! We have seen in this blog how to lock and unlock annotations using Syncfusion’s Xamarin.Forms PDF Viewer control. Try this in your application and share your feedback in the comment section below!

If you aren’t a customer, you can try our 30-day free trial to check out these features. Also, try our other Xamarin examples from this GitHub location.

If you have any questions, you can contact us through our support forum, support portal, or feedback portal. We are always happy to assist you!

Related blogs

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .