2

I have a C# Wpf project in which I have successfully loaded an Xps. file into a Document Viewer. I want to be able to have a variable in my C# code that notices a page change when you scroll the document. So far I have figured out, that there is a function for the xaml code, that automatically changes the page number if you scroll to the next page:

    <DocumentViewer x:Name="viewDocument" HorizontalAlignment="Left" VerticalAlignment="Top" Height="Auto" Grid.Row="0" Grid.Column="0" >
            <FixedDocument></FixedDocument>
        </DocumentViewer>
    <TextBlock Text="{Binding ElementName=viewDocument,Path=MasterPageNumber}" Grid.Row="1"/>

My final goal is to sto pthe time the user spends on each page which is why I need to be able to connect the current page number with a variable in my code which I cannot do with the above example. I have tried to implement an INotifyPropertyChanged, but I am fairly new to C# and I cannot find the error. it sets the variable to the first page, but after that it doesn't update.

This is my View Model:

using System; using System.ComponentModel; 
namespace Tfidf_PdfOnly {
public class MainViewModel : INotifyPropertyChanged
{

    private int _myLabel;

    public int MyLabel
    {
        get
        {
            return this._myLabel;
        }
        set
        {
            this._myLabel = value;
            NotifyPropertyChanged("MyLabel");
        }
    }


    public MainViewModel()
    {
        _myLabel = 55;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}
}

and this is in my Document_Viewer.xaml.cs file

 XpsDocument document1 = new XpsDocument(path, System.IO.FileAccess.Read);
        //load the file into the viewer
        viewDocument.Document = document1.GetFixedDocumentSequence();

        MainViewModel vm = new MainViewModel();
        this.DataContext = vm;
        vm.MyLabel = viewDocument.MasterPageNumber; 

To see if it works I bound it to a label on the UI:

<DocumentViewer x:Name="viewDocument" HorizontalAlignment="Left" VerticalAlignment="Top" Height="Auto" Grid.Row="0" Grid.Column="0" >
            <FixedDocument></FixedDocument>
        </DocumentViewer>
    <TextBlock Text="{Binding MyLabel, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" Grid.Row="1" HorizontalAlignment="Right"/>

I hope my question is clear, and any help is appreceated!

Lilly
  • 63
  • 4

1 Answers1

1

The DocumentViewer has a property named MasterPageNumber (which is supposed to be the page index of the document). The following sample uses Prism and the Blend SDK (behaviors). The converter is quick-and-dirty. For the timing, you could use StopWatch instances to track how long in between page changes.

MVVM Approach

ViewModel

public class ShellViewModel : BindableBase
{
    private int _currentPage;

    public string Title => "Sample";

    public string DocumentPath => @"c:\temp\temp.xps";

    public int CurrentPage
    {
        get => _currentPage;
        set => SetProperty(ref _currentPage, value);
    }

    public ICommand PageChangedCommand => new DelegateCommand<int?>(i => CurrentPage = i.GetValueOrDefault());
}

View

<Window x:Class="Poc.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:viewModels="clr-namespace:Poc.ViewModels"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:behaviors="clr-namespace:Poc.Views.Interactivity.Behaviors"
    xmlns:converters="clr-namespace:Poc.Views.Converters"
    xmlns:controls1="clr-namespace:Poc.Views.Controls"
    mc:Ignorable="d"
    Title="{Binding Title}" Height="350" Width="525">
<Window.Resources>
    <converters:PathToDocumentConverter x:Key="PathToDocumentConverter"></converters:PathToDocumentConverter>
</Window.Resources>
<Window.DataContext>
    <viewModels:ShellViewModel />
</Window.DataContext>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
    </Grid.RowDefinitions>
    <DocumentViewer Document="{Binding DocumentPath,Converter={StaticResource PathToDocumentConverter}}">
        <i:Interaction.Behaviors>
            <behaviors:DocumentViewerBehavior PageViewChangedCommand="{Binding PageChangedCommand}"></behaviors:DocumentViewerBehavior>
        </i:Interaction.Behaviors>
    </DocumentViewer>
    <TextBlock Grid.Row="1" Text="{Binding CurrentPage}"></TextBlock>
</Grid>

Behavior

public class DocumentViewerBehavior : Behavior<DocumentViewer>
{
    public static readonly DependencyProperty PageViewChangedCommandProperty = DependencyProperty.Register(nameof(PageViewChangedCommand), typeof(ICommand), typeof(DocumentViewerBehavior));

    public ICommand PageViewChangedCommand
    {
        get => (ICommand)GetValue(PageViewChangedCommandProperty);
        set => SetValue(PageViewChangedCommandProperty, value);
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.PageViewsChanged += OnPageViewsChanged;
    }

    private void OnPageViewsChanged(object sender, EventArgs e) => PageViewChangedCommand?.Execute(AssociatedObject.MasterPageNumber);

    protected override void OnDetaching()
    {
        base.OnDetaching();

        AssociatedObject.PageViewsChanged -= OnPageViewsChanged;
    }
}

Converter

public class PathToDocumentConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var fileInfo = new FileInfo((string)value);

        if (fileInfo.Exists)
        {
            if (String.Compare(fileInfo.Extension, ".XPS", StringComparison.OrdinalIgnoreCase) == 0)
            {
                return new XpsDocument(fileInfo.FullName, FileAccess.Read).GetFixedDocumentSequence();
            }
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Eric
  • 1,737
  • 1
  • 13
  • 17