3

I am building a WPF wrapper to display PDFs using Acrobat (from this CodePlex project)

The Codeplex project supplies enough samples on performing basic functions on the PDF Viewer, but lacks the functionalities of the WPF MVVM pattern. My WPF wrapper must expose dependency properties to modify the behaviour of the Acrobat PDF Viewer using Binding in Xaml.

Normal binding to proprties such as Filename, PageNumber, etc. is fine, as I am doing the following:

  1. Create the Dependency Property (Can be implemented relatively easy from the codeplex project)

    public static readonly DependencyProperty PdfPathProperty =
         DependencyProperty.Register("PdfPath", typeof(string), typeof(PdfViewer), new UIPropertyMetadata(null, LoadPDF));
    
    
    public string PdfPath {
        get {
            return (string)GetValue(PdfPathProperty);
        }
        set {
            SetValue(PdfPathProperty, value);
        }
    }
    
    private static void LoadPDF(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        var control = d as PdfViewer;
        if (control == null) return;
        control.LoadFile();
    }
    
    private void LoadFile() {
        _winFormPdfHost.LoadFile(PdfPath);
    }
    
  2. Where you use the UserControl, bind to the Dependency Property:

        <viewer:PdfViewer x:Name="viewer" PdfPath="{Binding FileName}" 
                          ShowToolbar="{Binding ShowToolbar, UpdateSourceTrigger=PropertyChanged}"
                          PageNumber="{Binding PageNumber, UpdateSourceTrigger=PropertyChanged}">
        </viewer:PdfViewer>
    

This is all working as expected. However, I need to somehow pass commands through to the Wrapper. For instance, I need to trigger an action/command such as 'GoToFirstPage', and this is where I am stuck.

I want to do something like the following:

        <viewer:PdfViewer x:Name="viewer" PdfPath="{Binding FileName}" 
                          ShowToolbar="{Binding ShowToolbar, UpdateSourceTrigger=PropertyChanged}"
                          PageNumber="{Binding PageNumber, UpdateSourceTrigger=PropertyChanged}"
                          FirstPageCommand="{Binding GoToFirstPageCommand}">
        </viewer:PdfViewer> 

However this approach wont work, because I don't want to implement the functionality of the command in the ViewModel. I just want to execute the function in the Wrapper.

I basically want to build a custom toolbar which will cater for the logic instead of using the toolbar that Acrobat offers, and I will need to be able to pass through, or trigger commands in the wrapper from the outside somehow.

Edit

I can accomplish this by ignoring MVVM, and only expose a public method from the Wrapper:

  1. In the wrapper - Remove the Dependency Property for the Command, and only expose the function:

    public void GoToFirstPage() {
        _winFormPdfHost.GoToFirstPage();
    }
    
  2. From the ViewModel, access the method through the UserControl

    private ICommand _FirstPageCommand;
    public ICommand FirstPageCommand {
        get {
            if (_FirstPageCommand == null) {
                _FirstPageCommand = CreateCommand(GoToFirstPage);
            }
            return _FirstPageCommand;
        }
    }
    
    public void GoToFirstPage(object obj) {
        var viewer = obj as WPFPdfViewer.PdfViewer;
        viewer.GoToFirstPage();
    }
    

with the wrapper as the command parameter:

    <Button VerticalAlignment="Center" Content="First" Padding="10,5,10,5" Margin="5" Command="{Binding FirstPageCommand}" CommandParameter="{Binding ElementName=viewer}"/>
Johan Aspeling
  • 765
  • 1
  • 13
  • 38
  • You could Expose another `DependencyProperty` of type `Boolean` (e.g. `GoToFirstPageTrigger`) and define a callback, which will execute the command logic. When you want to go to first page you set that property in the viewmodel to true. – user3292642 Jan 26 '17 at 10:30
  • I did think about that, but there must be a more elegant solution – Johan Aspeling Jan 26 '17 at 10:35
  • 1
    From a strict point of view it's not your ViewModel's job to change the page. You just want it to notify your PDF controller that it must change the page. To do this you could expose an event from your pdf controller and in your view model add a command that will fire this event when called. Or use event to command binding – yan yankelevich Jan 26 '17 at 10:54

0 Answers0