问题
In WPF I have a DocumentViewer inside a Frame control. The DocumentViewer shows an XPS document generated with MS Word. The document contains a Table of Content to help navigate through the document.
The DocumentViewer allows the user to click these links and navigate to the corresponding pages, as long as the DocumentViewer is placed in a control that allows for navigation (e.g. a Frame).
When the user navigates for the first time, the DocumentViewer does not jump accurately to the linked location. The further away in the document, the larger the space between the jumped location and the actual location becomes. It looks like it is off by a certain amount per page. After this first link click, the navigation works perfectly fine.
When navigating back using the navigation buttons on the frame, the link accuracy behaves pore again as soon as the very first view is loaded.
According to this post, a new DocumentViewer is being created after clicking on the link for the first time. It seems that that creates an instance that works as expected.
Why is the initial instance not navigating accurately and how to solve this?
The code snipped below can be used to reproduce the issue.
XAML inside a Window:
<Frame>
<Frame.Content>
<DocumentViewer Name="docViewer" />
</Frame.Content>
</Frame>
Code behind:
public MainWindow()
{
InitializeComponent();
LoadDoc();
}
private void LoadDoc()
{
XpsDocument xpsDoc = new XpsDocument("test.xps", FileAccess.Read);
docViewer.Document = xpsDoc.GetFixedDocumentSequence();
}
The test.xps document contains a TOC and two chapters with around 40 pages in between them. The issue becomes clear when navigating to the second chapter (it is off by 3 pages).
回答1:
After almost two years I've revisited this issue and found the solution.
As can be seen in my original post, I used a Frame
with its content set to a DocumentViewer
. The Frame
is used to enable navigation within the XPS document.
Some details:
When the document loads for the first time, the actual Content
of the Frame
is set to the DocumentViewer
. The Source
of the Frame
is null
. When clicking a link in the document, the Frame
navigates to the location, but has poor accuracy, as described in my question above. Behind the scenes, the Frame
has changed its Content
to an instance of FixedDocumentSequence
and its Source
is set to the clicked Uri
. From now on, the navigation works perfectly accurate.
The solution:
The solution is actually very simple. Instead of putting a DocumentViewer
inside the Frame
and setting the DocumentViewer.Document
property to the actual FixedDocumentSequence
, the Frame.Source
property should be set to the Uri
of the FixedDocumentSequence
.
FixedDocumentSequence
implements the explicit interface property IUriContext.BaseUri
that can be used to retrieve the Uri
.
In my code, I use a binding to set the source:
<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>
In code behind you could accomplish the same by doing this:
XpsDocument xpsDoc = new XpsDocument(Path, FileAccess.Read);
FixedDocumentSequence document = xpsDoc.GetFixedDocumentSequence();
frame.Source = ((System.Windows.Markup.IUriContext)document).BaseUri;
来源:https://stackoverflow.com/questions/29518575/wpf-documentviewer-navigate-using-internal-link-not-accurate-on-first-click