Reputation: 594
I need to use PdfViewer from some library. This library provides control for Android, IOS, UWP platforms but not for WPF platform. How to create a renderer only for WPF platform?
WPF renderer:
[assembly: ExportRenderer(typeof(PdfViewer), typeof(PdfViewerRenderer))]
public class PdfViewerRenderer : Xamarin.Forms.Platform.WPF.ViewRenderer<PdfViewer, WPF.PlatformImplementations.PdfViewer>
{
}
WPF control implementation:
namespace WPF.PlatformImplementations
{
public class PdfViewer
{
//custom implementation of pdf viewer for wpf
}
}
Net standard library contains PdfViewer which derives from SfPdfViewer from a library:
namespace Views
{
public class PdfViewer : SfPdfViewer
{
//implementation of pdf viewer using base class from multiplatform library
}
}
The above approach does not work for WPF and works for other platforms. When I change inheritance from SfPdfViewer to Xamarin.Forms.View then it works for WPF but obviously does not work for other platforms. So the problem is to make renderer mechanizm to recognize Views.PdfViewer as control based on Xamarin.Forms.View.
Upvotes: 3
Views: 478
Reputation: 13601
Every Xamarin.Forms
control has a accompanying renderer for each platform that needs to create an instance of a native control.
SfPdfViewer
is a xamarin-forms control that only represents the shared UI state, and interaction logic. It needs a corresponding native control to actually render the view and interact with WPF
platform.
In order to do that, first step would be to choose a WPF
based control for viewing PDF files. For this example I have used WPF Pdf Viewer by SyncFusion; but any other option - probably like an embedded WebView or an open-source option like PdfiumViewer should also work.
Install nuget package for Syncfusion.PdfViewer.WPF in WPF project
Wire up the with forms-element (SfPdfViewer
) with native-control (PdfViewerControl
) using platform renderer.
[assembly: ExportRenderer(typeof(SfPdfViewer), typeof(SfPdfViewerRenderer))]
namespace PdfViewer.Demo.WPF
{
public class SfPdfViewerRenderer
: ViewRenderer<SfPdfViewer, Syncfusion.Windows.PdfViewer.PdfViewerControl>
{
Syncfusion.Windows.PdfViewer.PdfViewerControl _nativeControl;
protected override void OnElementChanged(ElementChangedEventArgs<SfPdfViewer> e)
{
base.OnElementChanged(e);
// If new forms element attached, wire up the native control
if (e.NewElement != null)
{
_nativeControl = new Syncfusion.Windows.PdfViewer.PdfViewerControl();
SetNativeControl(_nativeControl);
}
// Otherwise perform some cleanup
else
{
if(_nativeControl != null)
{
_nativeControl.Unload();
_nativeControl = null;
}
}
UpdateNativeControlProperties();
}
/// <summary>
/// Basically sync property values from forms-element (SfPdfViewer)
/// to native-control (PdfViewerControl)
/// In this example - we only sync with 'input file stream'
/// </summary>
private void UpdateNativeControlProperties()
{
if (Element != null && Element.InputFileStream != null)
{
Control.Load(Element.InputFileStream);
}
else
{
Control.Unload();
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == nameof(SfPdfViewer.InputFileStream))
{
UpdateNativeControlProperties();
}
}
}
}
Upvotes: 3
Reputation: 5099
One way to do this is to create a CustomPdfViewer
interface in the Core project, and have individual implementations in each native project using Dependency injection.
In the native implementations for each of the iOS, Android, & UWP projects, just make it use the PdfViewer
library that works for you.
And then for WPF, just use the SfPdfViewer
instead.
Eg: You can take a look at the official documentation here on DependencyService with examples
Once you do this, you will have your solution. But if you want to go one step further and access the CustomPdfViewer
you created inside your XAML, you can use "XAML Markup Extensions" represented by the term local
as you can also see in the example here.
Upvotes: 0