WPF:Visual Studio 2008 设计器中的固定文档

发布于 2024-08-19 06:28:08 字数 736 浏览 3 评论 0原文

这是一个众所周知的错误,当您尝试在 XAML 中构造一个 FixedDocument。例如,以下代码片段

<DocumentViewer>
    <FixedDocument>
        <PageContent>
            <FixedPage Width="21.0cm" Height="29.7cm">
                <TextBlock>Hello World!</TextBlock>
            </FixedPage>
        </PageContent>
    </FixedDocument>
</DocumentViewer>

编译并运行得很好,但 Visual Studio 在错误列表中显示错误(属性“Pages”不支持“PageContent”类型的值。)这非常烦人。

我正在寻找一种解决方案,允许我在 Visual Studio 中的 XAML 文件中构建文档,而不会收到该错误消息。我找到了一种解决方法,我想在下面分享它作为答案,但我很好奇是否有更好(更优雅)的解决方案。

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

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

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

发布评论

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

评论(4

分开我的手 2024-08-26 06:28:08

作为解决方法,我将 DocumentViewer 以及页面
进入网格:

<Grid>
    <FixedPage Width="21.0cm" Height="29.7cm" x:Name="uiPage1">
        <TextBlock>Hello World!</TextBlock>
    </FixedPage>
    <DocumentViewer>
        <FixedDocument x:Name="uiReport">
        </FixedDocument>
    </DocumentViewer>
</Grid>

然后我将页面附加到 Loaded 中的 DocumentViewer
窗口事件:

VB 示例:

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# 示例:

((Grid)uiPage1.Parent).Children.Remove(uiPage1);
var content = new PageContent();
((IAddChild)content).AddChild(uiPage1);
uiReport.Pages.Add(content);

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);
眼中杀气 2024-08-26 06:28:08

我知道这个问题已经得到了回答,但我认为这个答案更好,因为它不需要您添加 DocumentView。

如果有一种方法可以通过键名称引用资源并使用 XAML 将它们放入固定文档中,请告诉我。我似乎找不到办法做到这一点,但也许这是可能的。

使用:

var doc = System.Windows.Application.LoadComponent(new Uri("/FixedDocumentExample.xaml", UriKind.Relative)) as FixedDocument;
doc.AddPages();

扩展方法:

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>

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>
能否归途做我良人 2024-08-26 06:28:08

更简洁的解决方法:

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

FixedDocument 的这个子类伪造了 Pages 属性,并将所有添加的页面重定向到其基类中的真实 Pages 属性。

用法:

<doc:XamlFixedDocument xmlns:doc="clr-namespace:Hillinworks.WPF.Document">
    <PageContent>
        <FixedPage Background="White">
            <TextBlock Text="hello, world" />
        </FixedPage>
    </PageContent>
</doc:XamlFixedDocument>

Hillinworks.WPF.Document 更改为 XamlFixedDocument 类所在的命名空间。

这还可以在设计时预览文档。

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.

狂之美人 2024-08-26 06:28:08

所以我在弄乱固定文档时遇到了同样的问题。我认为这可能是比其他人建议的更干净的解决方法。

因此基本上您应该按照 hillin 建议创建一个从 FixedDocument 派生的自定义类,并添加一个属性从该对象的 PageContents 获取 FixedDocument。但由于这些页面现在是另一个对象的可视子级,因此您应该使用 XmlReader 和 XmlWriter 类制作它们的副本。

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

现在,在 xaml 中,您可以轻松创建一个 CustomFixedDocument StaticResource 并将您的 DocumentViewer 绑定到它的“FixedDocument”属性。

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

现在这两个问题都已得到解决。有实时设计时预览,没有编译错误,并且可以打印输出。

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.

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