WPF: FixedDocument in Visual Studio 2008 Designer
It's a well-known bug that Visual Studio shows an error when you try to construct a FixedDocument
in XAML. For example, the following snippet
<DocumentViewer>
<FixedDocument>
<PageContent>
<FixedPage Width="21.0cm" Height="29.7cm">
<TextBlock>Hello World!</TextBlock>
</FixedPage>
</PageContent>
开发者_JAVA百科 </FixedDocument>
</DocumentViewer>
compiles and runs perfectly fine, but Visual Studio shows an error in the error list (Property 'Pages' does not support values of type 'PageContent'.
) This is quite annoying.
I'm looking for a solution that allows me to construct my documents in a XAML file in Visual Studio without getting that error message. I've found a workaround, which I'd like to share below as an answer, but I'm curious if there's a better (more elegant) solution around.
As a workaround, I put the DocumentViewer as well as the page into a grid:
<Grid>
<FixedPage Width="21.0cm" Height="29.7cm" x:Name="uiPage1">
<TextBlock>Hello World!</TextBlock>
</FixedPage>
<DocumentViewer>
<FixedDocument x:Name="uiReport">
</FixedDocument>
</DocumentViewer>
</Grid>
Then I attach the page to the DocumentViewer in the Loaded
event of the window:
VB example:
DirectCast(Me.uiPage1.Parent, Grid).Children.Remove(Me.uiPage1)
Dim content As New PageContent()
DirectCast(content, IAddChild).AddChild(Me.uiPage1)
Me.uiReport.Pages.Add(content)
C# example:
((Grid)uiPage1.Parent).Children.Remove(uiPage1);
var content = new PageContent();
((IAddChild)content).AddChild(uiPage1);
uiReport.Pages.Add(content);
I know this had already been answered, but I think this answer is nicer because it doesn't require you to add a DocumentView.
If there's a way to reference the resources by the key name and put them in the FixedDocument with XAML, please let me know. I can't seem to find a way to do that, but maybe it's possible.
Use:
var doc = System.Windows.Application.LoadComponent(new Uri("/FixedDocumentExample.xaml", UriKind.Relative)) as FixedDocument;
doc.AddPages();
Extension Method:
using System.Collections;
using System.Windows.Documents;
public static class FixedDocumentExtended {
public static void AddPages(this FixedDocument fixedDocument) {
var enumerator = fixedDocument.Resources.GetEnumerator();
while (enumerator.MoveNext()) {
var pageContent = ((DictionaryEntry)enumerator.Current).Value as PageContent;
if (pageContent != null) {
fixedDocument.Pages.Add(pageContent);
}
}
}
}
XAML:
<FixedDocument
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<FixedDocument.Resources>
<PageContent x:Key="page1">
<FixedPage Width="793.76" Height="1122.56">
<TextBlock Margin="50" Text="Page 1"/>
</FixedPage>
</PageContent>
<PageContent x:Key="page2">
<FixedPage Width="793.76" Height="1122.56">
<TextBlock Margin="50" Text="Page 2"/>
</FixedPage>
</PageContent>
</FixedDocument.Resources>
</FixedDocument>
A cleaner workaround:
[ContentProperty("Pages")]
public class XamlFixedDocument : FixedDocument
{
private ObservableCollection<PageContent> _pages;
public XamlFixedDocument()
{
this.Pages = new ObservableCollection<PageContent>();
}
public new ObservableCollection<PageContent> Pages
{
get => _pages;
set
{
_pages = value;
foreach (var page in _pages)
{
base.Pages.Add(page);
}
_pages.CollectionChanged += (o, e) =>
{
if (e.NewItems != null)
{
foreach (PageContent page in e.NewItems)
{
base.Pages.Add(page);
}
}
};
}
}
}
This subclass of FixedDocument
fakes a Pages
property and redirect all added pages to the real Pages
property in its base class.
Usage:
<doc:XamlFixedDocument xmlns:doc="clr-namespace:Hillinworks.WPF.Document">
<PageContent>
<FixedPage Background="White">
<TextBlock Text="hello, world" />
</FixedPage>
</PageContent>
</doc:XamlFixedDocument>
Change Hillinworks.WPF.Document
to the namespace where the XamlFixedDocument
class is located.
This also enables design-time preview of your document.
So I was messing with fixed documents and I came across the same problem. and I think this is maybe even a cleaner workaround than what others have suggested.
So basically you should create a custom class derived from FixedDocument
as hillin suggested, and add a property to get FixedDocument
from this object's PageContents
. but since these pages are now visual children of another object you should make a copy of them using XmlReader and XmlWriter classes.
[ContentProperty("Pages")]
public class CustomFixedDocument : FixedDocument
{
private ObservableCollection<PageContent> _pages;
public CustomFixedDocument()
{
this.Pages = new ObservableCollection<PageContent>();
}
public FixedDocument FixedDocument
{
get
{
var document = new FixedDocument();
foreach (var p in Pages)
{
var copy = XamlReader.Parse(XamlWriter.Save(p)) as PageContent;
document.Pages.Add(copy);
}
return document;
}
}
public new ObservableCollection<PageContent> Pages
{
get => _pages;
set
{
_pages = value;
foreach (var page in _pages)
{
base.Pages.Add(page);
}
_pages.CollectionChanged += (o, e) =>
{
if (e.NewItems != null)
{
foreach (PageContent page in e.NewItems)
{
base.Pages.Add(page);
}
}
};
}
}
}
now in the xaml you could easily create a CustomFixedDocument
StaticResource and bind your DocumentViewer
to the 'FixedDocument' property of it.
<Window x:Class="MyProject.DocumentWindow"
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:local="clr-namespace:MyProject"
mc:Ignorable="d"
Title="DocumentWindow" Height="450" Width="800" Loaded="Window_Loaded">
<Window.Resources>
<local:CustomFixedDocument x:Key="Report">
<PageContent>
<FixedPage Width="793.76" Height="1122.56">
<TextBlock Margin="50" Text="Page 1"/>
</FixedPage>
</PageContent>
<PageContent>
<FixedPage Width="793.76" Height="1122.56">
<TextBlock Margin="50" Text="Page 2"/>
</FixedPage>
</PageContent>
</local:CustomFixedDocument>
</Window.Resources>
<Grid>
<DocumentViewer x:Name="viewer" Document="{Binding Source={StaticResource Report}, Path=FixedDocument}"/>
</Grid>
Now both issues have been addressed. there is live design time preview with no compile errors and the output could be printed.
精彩评论