【问题标题】:WPF - Cloning datagrid does not preserve visual markupWPF - 克隆数据网格不保留视觉标记
【发布时间】:2014-05-19 00:11:02
【问题描述】:

我想打印多页的 XPS 文档。文档中的每一页都是同一个数据网格,但其 ItemSource 属性每次都不同。

我了解到我需要断开数据网格与其可视父级的连接,否则,它不会让我将其作为子级添加到 System.Windows.Documents.FixedPage 对象(我用来打印)。我决定根据suggestions on the web 为每个新绑定(序列化然后反序列化为新对象)克隆数据网格。

克隆无法正常工作。虽然它保留了数据,但 datagrid 视觉标记丢失了 - 所以在打印时,我只得到空页。我尝试differentways 进行克隆,但没有任何帮助。

请指教。

这是我的 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;
    }
}

【问题讨论】:

    标签: wpf xaml c#-4.0 datagrid


    【解决方案1】:

    我了解到 XamlWriter.Save() 方法存在局限性, [http://social.msdn.microsoft.com/Forums/en-US/fe627934-9e3d-49ca-bee6-5faabe7deb44/wpf-cloning-datagrid-does-not-preserve-visual-markup?forum=csharpgeneral&prof=required][1]

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-25
      • 2018-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-28
      • 1970-01-01
      相关资源
      最近更新 更多