WPF DocumentViewer:使用内部 link 导航在第一次点击时不准确

WPF DocumentViewer : Navigate using internal link not accurate on first click

在 WPF 中,我在 Frame 控件中有一个 DocumentViewer。 DocumentViewer 显示一个用 MS Word 生成的 XPS 文档。该文档包含 Table 的内容以帮助浏览文档。

DocumentViewer 允许用户单击这些 link 并导航到相应的页面,只要将 DocumentViewer 放置在允许导航的控件(例如框架)中即可。

当用户第一次导航时,DocumentViewer 不会准确跳转到 linked 位置。文档中越远,跳转位置与实际位置之间的 space 就越大。看起来每页都有一定数量的偏差。在第一次 link 单击后,导航工作正常。

使用框架上的导航按钮向后导航时,link 准确度在加载第一个视图后立即再次下降。

根据 this post,第一次单击 link 后会创建一个新的 DocumentViewer。这似乎创建了一个按预期工作的实例。

为什么初始实例导航不准确,如何解决?

下面截取的代码可用于重现该问题。

XAML 里面 Window:

<Frame>
    <Frame.Content>
        <DocumentViewer Name="docViewer" />
    </Frame.Content>
</Frame>

后面的代码:

    public MainWindow()
    {
        InitializeComponent();
        LoadDoc();
    }

    private void LoadDoc()
    {
        XpsDocument xpsDoc = new XpsDocument("test.xps", FileAccess.Read);
        docViewer.Document = xpsDoc.GetFixedDocumentSequence();
    }

test.xps 文档包含一个 TOC 和两章,它们之间有大约 40 页。导航到第二章时问题变得很清楚(关闭了 3 页)。

将近两年后,我重新审视了这个问题并找到了解决方案。

正如我原来的 post 中所见,我使用了一个 Frame,其内容设置为 DocumentViewerFrame 用于在 XPS 文档中启用导航。

一些细节:

第一次加载文档时,Frame 的实际 Content 设置为 DocumentViewerFrameSourcenull。单击文档中的 link 时,Frame 会导航到该位置,但准确性很差,如我上面的问题所述。在幕后,Frame 已将其 Content 更改为 FixedDocumentSequence 的实例,并将其 Source 设置为单击的 Uri。从现在开始,导航工作非常准确。

解决方法:

解决方法其实很简单。而不是将 DocumentViewer 放入 Frame 并将 DocumentViewer.Document 属性 设置为实际的 FixedDocumentSequenceFrame.Source 属性 应该设置为 FixedDocumentSequenceUri

FixedDocumentSequence 实现了可用于检索 Uri.

的显式接口 属性 IUriContext.BaseUri

在我的代码中,我使用绑定来设置源:

<UserControl x:Class="XPSDocumentView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:base="clr-namespace:System.Windows.Markup;assembly=System.Xaml" >

    <Grid>
        <Frame Margin="5" NavigationUIVisibility="Hidden" 
               Source="{Binding Path=Document.(base:IUriContext.BaseUri)}" />
    </Grid>

</UserControl>

在后面的代码中,您可以通过这样做来完成同样的事情:

XpsDocument xpsDoc = new XpsDocument(Path, FileAccess.Read);
FixedDocumentSequence document = xpsDoc.GetFixedDocumentSequence();
frame.Source = ((System.Windows.Markup.IUriContext)document).BaseUri;