在 MVVM 中绑定 DocumentViewer

发布于 2024-12-08 22:45:08 字数 1320 浏览 1 评论 0原文

我试图通过 ViewModel 将 DocumentViewer 绑定到文档,但根本没有成功。

这是我的视图模型代码...

    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()”以外的代码

我确实觉得奇怪的是,如果我将文档生成代码放在将视图模型构造函数放入视图构造函数中,文档会正确显示,这使我认为这是一个绑定问题,但我不知道在哪里或如何。

I'm trying to bind a DocumentViewer to a document via the ViewModel and am not succeeding at all.

Here is my view model code...

    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");
        }

    }

here is the xaml in the view...

<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>

the code behind for the view contains no code other than 'InitializeComponent()'

What I do find strange is that if I place the document generation code from the view model constructor into the view constructor the document is displayed correctly, this leads me to think it is a binding issue, but where or how I know not.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

难得心□动 2024-12-15 22:45:09

对于那些可能仍然不知道如何完成它的人。这是一个示例:

视图:

<Grid>
        <DocumentViewer HorizontalAlignment="Center" 
                        Margin="0,20,0,0"
                        Document="{Binding Manual}"
                        VerticalAlignment="Top" 
                        Height="508" Width="766" />
</Grid>

ViewModel:

public OperationManualViewModel()
{
    var _xpsPackage = new XpsDocument(@"C:\Users\me\Desktop\EngManual.xps", FileAccess.Read);
    _manual = _xpsPackage.GetFixedDocumentSequence();

}

private IDocumentPaginatorSource _manual;

public IDocumentPaginatorSource Manual
{
    get { return _manual; }
    set { _manual = value; NotifyOfPropertyChange(() => Manual); }
}

For people who might still have no clue how to get it done. Here is an example:

The View:

<Grid>
        <DocumentViewer HorizontalAlignment="Center" 
                        Margin="0,20,0,0"
                        Document="{Binding Manual}"
                        VerticalAlignment="Top" 
                        Height="508" Width="766" />
</Grid>

The ViewModel:

public OperationManualViewModel()
{
    var _xpsPackage = new XpsDocument(@"C:\Users\me\Desktop\EngManual.xps", FileAccess.Read);
    _manual = _xpsPackage.GetFixedDocumentSequence();

}

private IDocumentPaginatorSource _manual;

public IDocumentPaginatorSource Manual
{
    get { return _manual; }
    set { _manual = value; NotifyOfPropertyChange(() => Manual); }
}
夏天碎花小短裙 2024-12-15 22:45:08

您将 DocumentViewerDocument 属性绑定到名为 DocumentViewer1 的属性,该属性本身就是一个 DocumentViewerDocument 属性需要一个实现 IDocumentPaginatorSource 的类型实例,例如 固定文档

You are binding the Document property of the DocumentViewer to a property called DocumentViewer1 which is itself a DocumentViewer. The Document property expects an instance of a type that implements IDocumentPaginatorSource, such as a FixedDocument.

魔法少女 2024-12-15 22:45:08

如果您希望保持视图模型原始状态并避免在视图模型库中包含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"};

If you want to keep your view models pristine and avoid including PresentationCore.dll in your view model library, then use a WPF IValueConverter such as the following.

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.");
        }
    }
}

The XAML below shows how to use the above converter. This example is a data template that has a view model of Type MessageBoxShowXpsDoc which has a simple string property called DocumentPath. This is passed to the converter to obtain the 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>

Although including the full view model is outside the scope of the OP, this is an example of how I set that string path which is passed from the view model to the converter.

var viewModel = MessageBoxShowXpsDoc {DocumentPath = @"TestData\sample.xps"};
意犹 2024-12-15 22:45:08

正如 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>

As explained already by devdigital (above), a public property of type
IDocumentPaginatorSource is needed.

Something like this perhaps:

private IDocumentPaginatorSource _fixedDocumentSequence;

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

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

And in your xaml just bind this to the DocumentViewer Document property:

<Grid>
    <DocumentViewer                                          
        Name="DocViewer"
        Document="{Binding FixedDocumentSequence}"/>       
</Grid>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文