0

Good Morning!

I have a WPF application that will display a number of different file types based on command line args it receives. It works fine, but I want to go back and refactor it. I have only been a developer for a few years and would like to master MVVM.

I am using an MVVM design package called Stylet. In my PDF view I am using a Telerik RadPdfViewer control to which Telerik has all this binding stuff built in for you. For example, I am binding the right click context menu with the commands "select all" and "copy" using their pre configured command bindings.

I would like to bind the "Document Source" property TO MY viewmodel so I can pass in the paths of documents I want to load. However, the DataContext of the control is bound to Telerik's CommandDescriptors preventing the binding to my viewmodel.

<telerik:RadPdfViewer x:Name="radPdfViewer" Grid.Row="1" 
                          DataContext="{Binding CommandDescriptors, ElementName=radPdfViewer}" 
                          DocumentSource="{Binding PDFDoc}" 
                          telerik:RadPdfViewerAttachedComponents.RegisterFindDialog="True" 
                          HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" 
                          telerik:StyleManager.Theme="Office_Black" Grid.ColumnSpan="2">
        <telerik:RadContextMenu.ContextMenu>
            <telerik:RadContextMenu>
                <telerik:RadMenuItem Header="Select All" 
                                     Command="{Binding SelectAllCommandDescriptor.Command}" />
                <telerik:RadMenuItem Header="Copy" 
                                     Command="{Binding CopyCommandDescriptor.Command}" />
            </telerik:RadContextMenu>
        </telerik:RadContextMenu.ContextMenu>
    </telerik:RadPdfViewer>

public class PDFViewModel
{
    private string _pdfDoc;
    public string PDFDoc
    {
        get
        {
            return _pdfDoc;
        }
        set
        {
            _pdfDoc = value;
        }
    }
    public PDFViewModel()
    {
        PDFDoc = @"t:\share\large.pdf";
    }
}

I see two choices

  1. I break Telerik's prebuilt command bindings and figure out how to bring the select all and copy functions to my viewmodel.

  2. Stylet has an s:Action function where I can call a method where I can load the document into the RadPdfViewer control using C#. I would need to somehow get control of the gui control in the method of my viewmodel and I am not sure how to do that.

Is there a better way? A little nudge in the right direction would be greatly appreciated.

  • 1
    Is this control within a container you have access to? Window or otherwise? My thought is that you could bind your view model to the parent control, and then use relative or element name binding to bind `DocumentSource` to the parent's `DataContext`. But I'm not sure what you're working with so it's hard to say. – Jason Tyler Mar 09 '21 at 17:47
  • Thank you for your response. The parent control is a user control. This has its own viewmodel. Not sure if this is important, but I am using a ViewModel first MVVM pattern. So the user control is actually called from a root viewmodel with a conductor..the root view has a window. So in theory, the user control's datacontext should be set to the viewmodel already. But let me try this. – Jason Garner Mar 09 '21 at 23:15

1 Answers1

0

Jason Tyler's reply got me going in the right direction. Thank you!

So because I am using a ViewModel first pattern, I did not need to specify the DataContext of the user control like I thought...Its already set.

However, his suggestion of binding using the relative source and researching on how to do this (I have never used RelativeSource before..I am kinda new to this stuff) I came across this Stack post

How do I use WPF bindings with RelativeSource?

A Jeff Knight Posted a diagram of how ancestor binding works. Ancestor Binding

Using that, I was able to figure out the syntax and my document came right up and I can still use the right click context menu items that are bound to Telerik. So now my Xaml looks like this note how the Document source binding has changed.

<telerik:RadPdfViewer x:Name="radPdfViewer" Grid.Row="1" 
                          DataContext="{Binding CommandDescriptors, ElementName=radPdfViewer}" 
                          DocumentSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext.PDFDoc}" 
                          telerik:RadPdfViewerAttachedComponents.RegisterFindDialog="True" 
                          HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Stretch" 
                          telerik:StyleManager.Theme="Office_Black" Grid.ColumnSpan="2">
        <telerik:RadContextMenu.ContextMenu>
            <telerik:RadContextMenu>
                <telerik:RadMenuItem Header="Select All" 
                                     Command="{Binding SelectAllCommandDescriptor.Command}" />
                <telerik:RadMenuItem Header="Copy" 
                                     Command="{Binding CopyCommandDescriptor.Command}" />
            </telerik:RadContextMenu>
        </telerik:RadContextMenu.ContextMenu>
    </telerik:RadPdfViewer>