Binding PDFViewer to MVVM Byte Array

4 posts, 1 answers
  1. Sandra
    Sandra avatar
    3 posts
    Member since:
    Jul 2018

    Posted 04 Jul Link to this post

    I'm trying to using MVVM binding for the pdfviewer but the document always turns out blank.  I'm querying a DB field that contains the bytes of the PDF file and I'm trying to get it to display in the viewer (I've confirmed that the file is not malformed and it displays fine if I save it as a PDF to my desktop).

    Here are my MVVM properties:

    private RadFixedDocument _currentDocument;
    public RadFixedDocument CurrentDocument
    {
        get => _currentDocument; set => this.RaiseAndSetIfChanged(ref _currentDocument, value);
    }

     

    Here is the method I'm using to populate the CurrentDocument property:

    var sqlStr = @"select top 1 * from FileManager order by ID desc;";
    var file = await con.QuerySingleAsync<FMFile>(sqlStr);
    var fileBytes = file.FileContent.ToArray();  // this is type byte[] - I confirmed that it has the correct contents
    var ms = new MemoryStream(fileBytes); // ms gets filled properly
    FormatProviderSettings settings = new FormatProviderSettings(ReadingMode.AllAtOnce);
    PdfFormatProvider provider = new PdfFormatProvider(ms, settings);
    CurrentDocument = provider.Import();

     

    And here is how my XAML looks:

    <telerik:RadPdfViewerToolBar RadPdfViewer="{Binding ElementName=pdfViewer, Mode=OneTime}" />
    <telerik:RadPdfViewer x:Name="pdfViewer"
                                  Grid.Row="1"
                                  DocumentSource="{Binding CurrentDocument, Mode=TwoWay}" />

     

    However, nothing get's displayed in the viewer.  I confirmed that my VM is hooked up correctly as other property display just fine.  Any advice would be appreciated.

  2. Georgi
    Admin
    Georgi avatar
    11 posts

    Posted 05 Jul Link to this post

    Hi Sandra,

    You can bind the DocumentSource property of RadPdfViewer to a URI, string representing a URI or a stream (but not to RadFixedDocument instance directly) using the PdfDocumentSourceValueConverter as can be seen in the Binding the DocumentSource of RadPdfViewer section of the documentation. For example:
    <Window x:Class="FixedDocumentViewerDemoWpf.MainWindow"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
                 xmlns:fixed="clr-namespace:Telerik.Windows.Documents.Fixed;assembly=Telerik.Windows.Controls.FixedDocumentViewers"
                 DataContext="{Binding RelativeSource={RelativeSource Self}}">
      
        <Grid.Resources>
            <fixed:PdfDocumentSourceValueConverter x:Key="PdfDocumentSourceValueConverter" />
        </Grid.Resources>
      
        <telerik:RadPdfViewerToolBar RadPdfViewer="{Binding ElementName=pdfViewer, Mode=OneTime}" />
        <telerik:RadPdfViewer x:Name="pdfViewer"
                                  Grid.Row="1"
                                  DocumentSource="{Binding Path=ViewModel.CurrentDocument, Mode=TwoWay, Converter={StaticResource
                                  PdfDocumentSourceValueConverter}}" />
    </Window>

    I hope this helps.

    Regards,
    Georgi
    Progress Telerik
    Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which allow you to write beautiful native mobile apps using a single shared C# codebase.
  3. Sandra
    Sandra avatar
    3 posts
    Member since:
    Jul 2018

    Posted 05 Jul in reply to Georgi Link to this post

    Hi Georgi,

     

    Ok, when I change my property to be a Stream instead, an exception gets thrown that looks like its from one of the Telerik DLL's possibly.  I checked that my 'mStream' variable (which you'll see below) does have the bytes in it that it needs.  Here's the output:

    System.NullReferenceException
      HResult=0x80004003
      Message=Object reference not set to an instance of an object.
      Source=Telerik.Windows.Controls.FixedDocumentViewers
      StackTrace:
       at Telerik.Windows.Documents.Fixed.FixedDocumentStreamSource.ExecuteLoadAction(Action action)
       at Telerik.Windows.Documents.Fixed.FixedDocumentStreamSource.<>c__DisplayClass8.<LoadDocument>b__6()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

     

    And here's how I changed my code:

    private Stream _currentDocument;
    public Stream CurrentDocument
    {
      get => _currentDocument; set => this.RaiseAndSetIfChanged(ref _currentDocument, value);

    }

     

    And my populate function:

    private void LoadFile()
            {
                using (var con = _mb.sqlHelper.OpenSysproDbConnection())
                {
                    var sqlStr = @"select top 1 * from FileManager order by ID desc;";
                    var file = con.QuerySingle<FMFile>(sqlStr);
                    var fileBytes = file.FileContent.ToArray();
                    MemoryStream mStream = new MemoryStream(fileBytes);
                    CurrentDocument = mStream;
                }
            }

     

    As for my view, I'm using the same code that you have there for the converter.

  4. Answer
    Georgi
    Admin
    Georgi avatar
    11 posts

    Posted 10 Jul Link to this post

    Hello Sandra,

    I've investigated the code in FixedDocumentStreamSource.ExecuteLoadAction, and it seems that the NullReferenceException is thrown because the WPF's Application.Current property is still null. The following could cause such issue:
    1. The DocumentSource property is bound before the WPF's Application instance has been created (it's typically created in the automatically generated Main method in the WPF application assembly).
    2. The view containing the RadPdfViewer is used in a non-WPF application, so the Application instance is never set.

    Possible workaround would be to set an Application.Current instance before the document is actually loaded and observe if the exception still occurs. This could be achieved by just creating an Application instance somewhere before the problematic code:
    new System.Windows.Application();

    Note that you don't have to set the created instance anywhere, it will automatically set itself to the Application.Current property.

    I hope this helps.

    Regards,
    Georgi
    Progress Telerik
    Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which allow you to write beautiful native mobile apps using a single shared C# codebase.
Back to Top