WPF-克隆datagrid不会保留可视标记

WPF-克隆datagrid不会保留可视标记,wpf,xaml,c#-4.0,datagrid,Wpf,Xaml,C# 4.0,Datagrid,我想打印多页的XPS文档。文档中的每个页面都是相同的datagrid,但其ItemSource属性每次都不同 我了解到我需要断开datagrid与其可视化父对象的连接,因为否则,它将不允许我将其作为子对象添加到System.Windows.Documents.FixedPage对象(我用于打印)。我决定为每个新绑定克隆datagrid(序列化,然后反序列化为新对象) 克隆工作不正常。虽然它保留了数据,但是datagrid可视标记丢失了——因此在打印时,我只得到了空页面。我试图克隆,但没有任何帮助

我想打印多页的XPS文档。文档中的每个页面都是相同的datagrid,但其ItemSource属性每次都不同

我了解到我需要断开datagrid与其可视化父对象的连接,因为否则,它将不允许我将其作为子对象添加到System.Windows.Documents.FixedPage对象(我用于打印)。我决定为每个新绑定克隆datagrid(序列化,然后反序列化为新对象)

克隆工作不正常。虽然它保留了数据,但是datagrid可视标记丢失了——因此在打印时,我只得到了空页面。我试图克隆,但没有任何帮助

请告知

这是我的xaml:

<Window x:Class="TestDataGridVisual.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" >
<Grid Name="TestGrid">
    <DataGrid Name="dgUsers" AutoGenerateColumns="False" CanUserAddRows="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
            <DataGridTextColumn Header="Birthday" Binding="{Binding Birthday}" />
        </DataGrid.Columns>
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Details}" Margin="10" />
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
    <Grid>
        <Button Content="Print" Height="23" HorizontalAlignment="Center"  Name="printButton" VerticalAlignment="Top" Width="75" Margin="71,282,0,0" Click="printButton_Click" />
    </Grid>      
</Grid>

以下是我的代码:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    List<List<User>> dataset = new List<List<User>>()
    {
        new List<User> () {new User() {Id = 1, Name = "John Doe", Birthday = new DateTime(1971, 7, 23)}}, //for page1
        new List<User> () {new User() { Id = 2, Name = "Jane Doe", Birthday = new DateTime(1974, 1, 17)}} //for page2
    };

    public MainWindow()
    {
        InitializeComponent();
        dgUsers.ItemsSource = dataset[0];
    }

    private void printButton_Click(object sender, RoutedEventArgs e)
    {
        PrintDialog printDialog = new PrintDialog();

        //We want to change bindings on the same element and print each in a new page
        FixedDocument fixedDocument = new FixedDocument();
        var documentPageSize = new Size(8.26 * 96, 11.69 * 96); // A4 page, at 96 dpi
        fixedDocument.DocumentPaginator.PageSize = documentPageSize;

        //Keep changing binding of ItemSource and append the resulting visual to the fixedDocument as a new page
        foreach(var data in dataset)
        {
            dgUsers.ItemsSource = data;
            dgUsers.UpdateLayout();

            //I have to clone the datagrid since otherwise it gives this message:
            //"Specified element is already the logical child of another element. Disconnect it first."
            //But for some reason, cloning the datagrid loses its visual markup although it has data
            //Hence an empty page prints - So how do I fix the cloning ?
            var pageContent = GetPageContent(CloneDataGrid(dgUsers), documentPageSize);
            fixedDocument.Pages.Add(pageContent);
        }

        printDialog.PrintDocument(fixedDocument.DocumentPaginator, "Test Document");            
    }

    private PageContent GetPageContent(Visual visual, Size pageSize)
    {
        // Create FixedPage
        var fixedPage = new FixedPage();
        fixedPage.Width = pageSize.Width;
        fixedPage.Height = pageSize.Height;

        // Add visual, measure/arrange page.
        fixedPage.Children.Add((UIElement)visual);
        fixedPage.Measure(pageSize);
        fixedPage.Arrange(new Rect(new Point(5.0, 5.0), pageSize));
        fixedPage.UpdateLayout();

        // Add page to document
        var pageContent = new PageContent();
        ((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);

        return pageContent;
    }

    private DataGrid CloneDataGrid(DataGrid inputVisual)
    {
        DataGrid clonedVisual;
        //Problem seems to be in this method
        //I try to serialize input visual as string
        //But if I inspect this string, it loses all visual markup - has only the data - why ?
        //Hence this functions ends up returning a visually empty datagrid on de-serializing
        string inputVisualAsString = System.Windows.Markup.XamlWriter.Save(inputVisual);
        if (inputVisualAsString == null) return null;

        //Write the string into a memory stream and read it into a new Visual
        using (System.IO.MemoryStream stream = new System.IO.MemoryStream(inputVisualAsString.Length))
        using (System.IO.StreamWriter sw = new System.IO.StreamWriter(stream))
        {
            sw.Write(inputVisualAsString);
            sw.Flush();
            stream.Seek(0, System.IO.SeekOrigin.Begin);

            //Load from memory stream into a new Visual - On the WPF viewer, the grid looks empty since serialization did not have all the wpf markup.
            clonedVisual = System.Windows.Markup.XamlReader.Load(stream) as DataGrid;
        }

        return clonedVisual;
    }
}
//
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
列表数据集=新列表()
{
新列表(){new User(){Id=1,Name=“John Doe”,生日=new DateTime(1971,7,23)},//用于第1页
新列表(){new User(){Id=2,Name=“Jane Doe”,生日=new DateTime(1974,1,17)}//
};
公共主窗口()
{
初始化组件();
dgUsers.ItemsSource=数据集[0];
}
私有无效打印按钮\单击(对象发送者,路由目标e)
{
PrintDialog PrintDialog=新建PrintDialog();
//我们希望更改同一元素上的绑定,并在新页面中打印每个绑定
FixedDocument FixedDocument=新的FixedDocument();
var documentPageSize=新大小(8.26*96,11.69*96);//A4页,96 dpi
fixedDocument.DocumentPaginator.PageSize=documentPageSize;
//不断更改ItemSource的绑定,并将生成的可视内容作为新页面附加到fixedDocument
foreach(数据集中的var数据)
{
dgUsers.ItemsSource=数据;
dgUsers.UpdateLayout();
//我必须克隆datagrid,否则会显示以下消息:
//“指定的元素已经是另一个元素的逻辑子元素。请先断开它。”
//但出于某种原因,克隆datagrid会丢失其可视标记,尽管它有数据
//因此打印的是一个空白页,那么如何修复克隆呢?
var pageContent=GetPageContent(CloneDataGrid(dgUsers),documentPageSize);
fixedDocument.Pages.Add(页面内容);
}
printDialog.PrintDocument(fixedDocument.DocumentPaginator,“测试文档”);
}
private PageContent GetPageContent(可视大小、页面大小)
{
//创建固定页面
var fixedPage=new fixedPage();
fixedPage.Width=pageSize.Width;
fixedPage.Height=pageSize.Height;
//添加视觉、测量/排列页面。
fixedPage.Children.Add((UIElement)visual);
固定页面。测量(页面大小);
fixedPage.Arrange(新的Rect(新的点(5.0,5.0),pageSize));
fixedPage.UpdateLayout();
//向文档中添加页面
var pageContent=new pageContent();
((System.Windows.Markup.IAddChild)pageContent.AddChild(fixedPage);
返回页面内容;
}
专用DataGrid CloneDataGrid(DataGrid inputVisual)
{
数据网格克隆可视化;
//这个方法似乎有问题
//我尝试将输入可视化序列化为字符串
//但是如果我检查这个字符串,它会丢失所有可视标记-只有数据-为什么?
//因此,此函数在反序列化时返回一个可视为空的数据网格
string inputVisualAsString=System.Windows.Markup.XamlWriter.Save(InputVisualString);
如果(inputVisualAsString==null)返回null;
//将字符串写入内存流,并将其读入新的可视文件
使用(System.IO.MemoryStream stream=new System.IO.MemoryStream(inputVisualAsString.Length))
使用(System.IO.StreamWriter sw=新的System.IO.StreamWriter(流))
{
软件写入(输入字符串);
sw.Flush();
Seek(0,System.IO.SeekOrigin.Begin);
//从内存流加载到新的可视化视图中—在WPF查看器上,网格看起来是空的,因为序列化没有所有WPF标记。
clonedVisual=System.Windows.Markup.XamlReader.Load(stream)as DataGrid;
}
返回克隆视觉;
}
}

我了解到XamlWriter.Save()方法存在局限性, [

我没有使用视觉克隆,而是采用以下方法

private void printButton_Click(object sender, RoutedEventArgs e)
{
    PrintDialog printDialog = new PrintDialog();

    //We want to change bindings on the same element and print each in a new page
    FixedDocument fixedDocument = new FixedDocument();
    var documentPageSize = new Size(8.26 * 96, 11.69 * 96); // A4 page, at 96 dpi
    fixedDocument.DocumentPaginator.PageSize = documentPageSize;

    //Keep changing binding of ItemSource and append the resulting visual to the fixedDocument as a new page
    foreach(var data in dataset)
    {
        MainWindow mw = new MainWindow();//I create a new object for each page and change its binding.

       mw.dgUsers.ItemsSource = data;

        mw.dgUsers.UpdateLayout();

        var pageContent = GetPageContent(CloneDataGrid(dgUsers), documentPageSize);
        fixedDocument.Pages.Add(pageContent);
    }

    printDialog.PrintDocument(fixedDocument.DocumentPaginator, "Test Document");            
}