Связывание DocumentViewer в MVVM - PullRequest
       33

Связывание DocumentViewer в MVVM

1 голос
/ 08 октября 2011

Я пытаюсь привязать DocumentViewer к документу через ViewModel, и у меня ничего не получается.

Вот мой код модели представления ...

    private DocumentViewer documentViewer1 = new DocumentViewer();

    public DocumentViewerVM()
    {
        string fileName = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "Here an xps document.xps");
        XpsDocument document = new XpsDocument(fileName, FileAccess.Read);            
        documentViewer1.Document = document.GetFixedDocumentSequence();            
        document.Close();

    }

    public DocumentViewer DocumentViewer1
    {
        get
        { return documentViewer1; }
        set
        {
            documentViewer1 = value;
            OnPropertyChanged("DocumentViewer1");
        }

    }

здесьxaml в представлении ...

<UserControl x:Class="DemoApp.View.DocumentViewerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
    <Grid>
        <DocumentViewer Name="DocumentViewer1" Document="{Binding Path=DocumentViewer1, UpdateSourceTrigger=PropertyChanged}" ></DocumentViewer>

    </Grid>
</UserControl>

код для представления не содержит никакого кода, кроме 'InitializeComponent ()'

Что я нахожу странным, так это то, что если я помещаюКод генерации документа из конструктора модели представления в конструктор представления документа отображается правильно, это заставляет меня думать, что это проблема связывания, но где или как я не знаю.

Ответы [ 3 ]

3 голосов
/ 10 октября 2011

Вы связываете свойство Document DocumentViewer со свойством с именем DocumentViewer1, которое само по себе является DocumentViewer. Свойство Document ожидает экземпляр типа, который реализует IDocumentPaginatorSource, например FixedDocument .

0 голосов
/ 05 июля 2018

Если вы хотите сохранить ваши модели представлений нетронутыми и избегайте включения PresentationCore.dll в библиотеку моделей представлений , тогда используйте WPF IValueConverter , например, следующее.

namespace Oceanside.Desktop.Wpf.Dialogs.Converters
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Xps.Packaging;

    ////////////////////////////////////////////////////////////////////////////////////////////////////
    /// <inheritdoc />
    /// <summary>
    ///     Our view models contain string paths to all XPS documents that we want to show.  However,
    ///     the DocumentViewer.Document property must be of type IDocumentPaginatorSource which we do
    ///     not want to include in our view model because it will tie our view models to the
    ///     PresentationCore.dll.  To assure all view logic and libraries are kept separate from our
    ///     view model, this converter to take a string path and convert it to a
    ///     FixedDocumentSequence which implements the IDocumentPaginatorSource interface.
    /// </summary>
    ////////////////////////////////////////////////////////////////////////////////////////////////////

    [ValueConversion(typeof(string), typeof(IDocumentPaginatorSource))]
    public sealed class DocumentPaginatorSourceConverter : IValueConverter
    {
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <inheritdoc />
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        public object Convert(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            if (!(value is string xpsFilePath)) return null;

            var document = new XpsDocument(xpsFilePath, FileAccess.Read);
            var source = document.GetFixedDocumentSequence();
            document.Close();
            return source;
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <inheritdoc />
        /// <summary>This function is not supported and will throw an exception if used.</summary>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        public object ConvertBack(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            //We have no use to convert from IDocumentPaginatorSource to a string path.  
            throw new NotSupportedException("Unable to convert an IDocumentPaginatorSource to a string path.");
        }
    }
}

XAML ниже показывает, как использовать вышеуказанный конвертер.Этот пример представляет собой шаблон данных, имеющий модель представления типа MessageBoxShowXpsDoc, которая имеет простое строковое свойство с именем DocumentPath.Это передается конвертеру для получения IDocumentPaginatorSource.

<!-- For showing xps/flow docs such as customer receipts -->
<DataTemplate 
       DataType="{x:Type dialogVms:MessageBoxShowXpsDoc}"
       xmlns:converters="clr-namespace:Oceanside.Desktop.Wpf.Dialogs.Converters">
    <DataTemplate.Resources>
        <converters:DocumentPaginatorSourceConverter x:Key="DocPagConverter" />
    </DataTemplate.Resources>
    <DocumentViewer Document="{Binding DocumentPath, 
                               Converter={StaticResource DocPagConverter}}" />
</DataTemplate>

Хотя включение модели полного представления выходит за рамки OP, это пример того, как я устанавливаю тот путь строки, который передается изсмотреть модель на конвертер.

var viewModel = MessageBoxShowXpsDoc {DocumentPath = @"TestData\sample.xps"};
0 голосов
/ 05 января 2017

Как уже объяснялось в devdigital (выше), необходимо публичное свойство типа IDocumentPaginatorSource.

Возможно, что-то вроде этого:

private IDocumentPaginatorSource _fixedDocumentSequence;

public IDocumentPaginatorSource FixedDocumentSequence
{
    get { return _fixedDocumentSequence; }
    set
    {
        if (_fixedDocumentSequence == value) return;

        _fixedDocumentSequence = value;
        OnPropertyChanged("FixedDocumentSequence");
    }
}

А в вашем xaml просто привяжите это к свойству DocumentViewer Document:

<Grid>
    <DocumentViewer                                          
        Name="DocViewer"
        Document="{Binding FixedDocumentSequence}"/>       
</Grid>
...