> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/xamarin/guides/xamarin-forms-document-viewer.md).

# Document viewer for Xamarin.Forms (fully featured)

Learn how to customize a ContentPage in Xamarin with Microsoft's guide. Understand rendering on different platforms using ContentPage, ExportRenderer, and PageRenderer. Click for complete sample code!

Before you get started, we recommend you have a look at Microsoft's comprehensive guide on [Customizing a ContentPage](https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/contentpage/). It is important that you understand how Xamarin renders the same page on different platforms using `ContentPage`, `ExportRenderer` and `PageRenderer`. In this guide, you will learn how to create a fully featured document viewer and editor as page renderer on each platform.

Complete sample code can be found here:

<a href="https://github.com/ApryseSDK/xamarin-forms-sample" class="button primary">Get Xamarin.Forms sample</a>

The rendering process can be taken advantage of to implement platform-specific customization by creating a custom renderer for a `ContentPage` on each platform. The process for doing this is as follows:

1. [Create](/xamarin/guides/xamarin-forms.md#creating-the-xamarinforms-page) a Xamarin.Forms page.
2. [Consume](/xamarin/guides/xamarin-forms.md#consuming-the-xamarinforms-page) the page from Xamarin.Forms.
3. [Create](/xamarin/guides/xamarin-forms.md#creating-the-page-renderer-on-each-platform) the custom renderer for the page on each platform.

## Create the Xamarin.Forms Page

An unaltered `ContentPage` can be added to the shared Xamarin.Forms project, as shown in the following XAML code example:

{% tabs %}
{% tab title="XAML" %}
{% code lineNumbers="true" %}

```xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="CustomRenderer.AdvancedViewerPage" Title="Advanced Viewer Page">
    <ContentPage.Content>
    </ContentPage.Content>
</ContentPage>
```

{% endcode %}
{% endtab %}
{% endtabs %}

Similarly, the code-behind file for the `ContentPage` should also remain unaltered, as shown in the following code example:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
public partial class AdvancedViewerPage : ContentPage
    {
        public AdvancedViewerPage()
        {
            // Document viewer contains toolbar, let's hide the global one
            NavigationPage.SetHasNavigationBar(this, false);
            InitializeComponent();
        }
    }
```

{% endcode %}
{% endtab %}
{% endtabs %}

An instance of the `AdvancedViewerPage` will be used to display document viewer on each platform. Customization of the control will be carried out in the custom renderer, so no additional implementation is required in the `AdvancedViewerPage` class.

## Consume the Xamarin.Forms Page

The empty `AdvancedViewerPage` must be displayed by the Xamarin.Forms application. This occurs when a button on the `MainPage` instance is tapped, which in turn executes the `OnOpenAdvancedViewerButtonClicked` method, as shown in the following code example:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
async void OnOpenAdvancedViewerButtonClicked(object sender, EventArgs e)
{
    await Navigation.PushAsync(new AdvancedViewerPage());
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

This code simply navigates to the `AdvancedViewerPage`, on which custom renderers will customize the page's appearance on each platform.

## Create the Page Renderer on each Platform

The `AdvancedViewerPage` instance is rendered by platform-specific `AdvancedViewerPageRenderer` classes, which all derive from the `PageRenderer` class for that platform. This results in each `AdvancedViewerPage` instance being rendered with document viewer, as shown in the following GIF:

| Android                                                                                                                                                                                                                                        | iOS                                                                                                                                                                                                                                            |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ![](https://653871032-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgjsBtuYmcKhWOdM9VCg4%2Fuploads%2Fgit-blob-d0ab7609f4d5e391afb8b856549530c34b1c23a8%2Fe329be619c04a50cae5ca40b4d674d92e3f3e080-453x814.gif?alt=media) | ![](https://653871032-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgjsBtuYmcKhWOdM9VCg4%2Fuploads%2Fgit-blob-3a3544e6d5926ac73368ed2588775e2b3e4435e2%2F05fd755dc5bf6fd10e5af490fd4c77a439d368b4-342x763.gif?alt=media) |

### Create the Page Renderer on iOS

The following code example shows the page renderer for the iOS platform:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
[assembly: ExportRenderer(typeof(AdvancedViewerPage), typeof(AdvancedViewerPageRenderer))]
namespace CustomRenderer.iOS
{
    public class AdvancedViewerPageRenderer : PageRenderer
    {
        private PTTabbedDocumentViewController mTabViewController;

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null || Element == null)
            {
                return;
            }

            try
            {
                SetupUserInterface();
                SetupEventHandlers();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(@" ERROR: ", ex.Message);
            }
        }

        //...
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

where the document viewer can be setup as follows:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
void SetupUserInterface()
{
    mTabViewController = new PTTabbedDocumentViewController();
    UINavigationController navigationController = new UINavigationController(mTabViewController);

    AddChildViewController(navigationController);

    View.AddSubview(navigationController.View);

    navigationController.DidMoveToParentViewController(this);

    NSUrl fileURL = NSBundle.MainBundle.GetUrlForResource("sample", "pdf");

    mTabViewController.OpenDocumentWithURL(fileURL);
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Create the Page Renderer on Android

The following code example shows the page renderer for the Android platform:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
[assembly: ExportRenderer(typeof(AdvancedViewerPage), typeof(AdvancedViewerPageRenderer))]
namespace CustomRenderer.Droid
{
    public class AdvancedViewerPageRenderer : PageRenderer
    {
        private DocumentView mDocumentView;

        public ViewerPageRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null || Element == null)
            {
                return;
            }

            try
            {
                SetupUserInterface();
                SetupEventHandlers();
                AddView(view);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(@" ERROR: ", ex.Message);
            }
        }

        //...
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

where the document viewer can be setup as follows:

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
void SetupUserInterface()
{
    activity = this.Context as Activity;
    view = activity.LayoutInflater.Inflate(Resource.Layout.AdvancedViewerLayout, this, false);

    mDocumentView = view.FindViewById<DocumentView>(Resource.Id.document_view);

    var context = this.Context;
    FragmentManager childManager = null;
    if (context is AppCompatActivity)
    {
        var activity = context as AppCompatActivity;
        var manager = activity.SupportFragmentManager;

        var fragments = manager.Fragments;
        if (fragments.Count > 0)
        {
            childManager = fragments[0].ChildFragmentManager;
        }
        if (childManager != null)
        {
            mDocumentView.OpenDocument(GetFile(), "", GetConfig(), childManager);
        }
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Click [here for ](https://github.com/ApryseSDK/xamarin-forms-sample/blob/master/ContentPage/Droid/DocumentView.cs)[`DocumentView`](https://github.com/ApryseSDK/xamarin-forms-sample/blob/master/ContentPage/Droid/DocumentView.cs)[ class](https://github.com/ApryseSDK/xamarin-forms-sample/blob/master/ContentPage/Droid/DocumentView.cs) implementation.

## Configure the Viewer

The document viewer is highly customizable and can be configured to remove/modify many components.

* For Android please see [this guide.](/xamarin/basic-operations/basics/fragment-config.md)
* For iOS, please see [this guide.](/xamarin/basic-operations/basics/viewer/viewer-configuration.md)

## Sample

Try out the complete sample here: [https://github.com/ApryseSDK/xamarin-forms-sample](https://github.com/ApryseSDK/xamarin-forms-sample/).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.apryse.com/xamarin/guides/xamarin-forms-document-viewer.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
