简体   繁体   中英

Is it possible to add a FlowDocument or Paragraph and Tables in a ContainerVisual?

I've been following this example to add header and footer in my DocumentPage and it looks like in this fuction I can add header and footer:

public override DocumentPage GetPage(int pageNumber)
{
    var oldPage = paginator.GetPage(pageNumber);
    var visual = new ContainerVisual();
    var face = new Typeface("Times New Roman");
    var header = new DrawingVisual();
    var footer = new DrawingVisual();

    using (var dc = header.RenderOpen())
        dc.DrawText(new FormattedText("Header", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, face, 14, Brushes.Black), new Point(0, 0));

    using (var dc = footer.RenderOpen())
        dc.DrawText(new FormattedText("Page " + (pageNumber + 1).ToString(), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, face, 14, Brushes.Black), new Point(720, 1023));

    visual.Children.Add(header);
    visual.Children.Add(oldPage.Visual);
    visual.Children.Add(footer);

    return new DocumentPage(visual);
}

for the header part I don't want that DrawingVisual . I want to add the following parts, a Paragraph and 2 Table , of my FlowDocument as the header for all pages:

var fd = new FlowDocument();
fd.PageWidth = 816;
fd.PageHeight = 1123.2;
fd.PagePadding = new Thickness(96);

var para = new Paragraph(new Run("Trade Report"));
para.TextAlignment = TextAlignment.Center;
para.FontWeight = FontWeights.Bold;
para.FontSize = 24;
fd.Blocks.Add(para);

var table1 = new Table();
table1.Margin = new Thickness(0, 24, 0, 24);
var rowGroup1 = new TableRowGroup();
rowGroup1.FontWeight = FontWeights.Bold;
var row1 = new TableRow();

var codeCell = new TableCell(new Paragraph(new Run("Customer Code: " + CustomerCode)));
codeCell.TextAlignment = TextAlignment.Left;
row1.Cells.Add(codeCell);

var dateCell = new TableCell(new Paragraph(new Run("Date: " + DateTime.Now.ToShortDateString())));
dateCell.TextAlignment = TextAlignment.Right;
row1.Cells.Add(dateCell);

rowGroup1.Rows.Add(row1);
table1.RowGroups.Add(rowGroup1);
fd.Blocks.Add(table1);

var table2 = new Table();
table2.CellSpacing = 0;
var rowGroup2 = new TableRowGroup();
rowGroup2.FontWeight = FontWeights.Bold;
var row2 = new TableRow();
row2.Background = new SolidColorBrush(Colors.LightGray);

foreach (var head in headers)
{
    var cell = new TableCell(new Paragraph(new Run(head)));
    if (head == "Quantity" || head == "Price" || head == "Value") cell.TextAlignment = TextAlignment.Right;
    else cell.TextAlignment = TextAlignment.Center;

    cell.BorderBrush = new SolidColorBrush(Colors.Black);
    cell.BorderThickness = new Thickness(0, 1, 0, 1);
    row2.Cells.Add(cell);
}
rowGroup2.Rows.Add(row2);
table2.RowGroups.Add(rowGroup2);
fd.Blocks.Add(table2);

How to do that?


EDIT

Feels like something similar to these:

var t1 = new TextBlock() { Text = "Some Text 1", FontWeight = FontWeights.Bold };
var t2 = new TextBlock() { Text = "Some Text 2", FontWeight = FontWeights.SemiBold };
var t3 = new TextBlock() { Text = "Some Text 3"};
var t4 = new TextBlock() { Text = "Some Text 4"};

var canvas = new Grid() { Width = oldPage.Size.Width};
canvas.ColumnDefinitions.Add(new ColumnDefinition());
canvas.ColumnDefinitions.Add(new ColumnDefinition());
canvas.ColumnDefinitions.Add(new ColumnDefinition());
canvas.ColumnDefinitions.Add(new ColumnDefinition());

Grid.SetColumn(t1, 0);
Grid.SetColumn(t2, 1);
Grid.SetColumn(t3, 2);
Grid.SetColumn(t4, 3);

canvas.Children.Add(t1);
canvas.Children.Add(t2);
canvas.Children.Add(t3);
canvas.Children.Add(t4);

canvas.Measure(new Size(oldPage.Size.Width, oldPage.Size.Height));
canvas.Arrange(new Rect(canvas.DesiredSize));
var size = new Size() { Height = canvas.ActualHeight, Width = canvas.ActualWidth };

using (var dc = header.RenderOpen())
{
    var brush = new VisualBrush(canvas);
    dc.DrawRectangle(brush, null, new Rect(size));
}
visual.Children.Add(header);

is the best solution for printing and it appears that I can add anything (StackPanel, DockPanel, Canvas, ViewBox etc.) to DocumentPage with VisualBrush , not bad!

is there anything better?

So to solve the problem I've extended the DocumentPaginator in this way:

public class FlowPaginator : DocumentPaginator
{
    string[] headers = { "Trans No.", "Order No.", "Type", "Price", "Quantity", "Value" };
    int code;
    DocumentPaginator paginator;
    public FlowPaginator(FlowDocument doc, int customerCode)
    {
        code = customerCode;
        paginator = ((IDocumentPaginatorSource)doc).DocumentPaginator;
    }
    public override bool IsPageCountValid => paginator.IsPageCountValid;
    public override int PageCount => paginator.PageCount;
    public override Size PageSize { get => paginator.PageSize; set => paginator.PageSize = value; }
    public override IDocumentPaginatorSource Source => paginator.Source;

    public override DocumentPage GetPage(int pageNumber)
    {
        var oldPage = paginator.GetPage(pageNumber);

        var visual = new ContainerVisual();
        var header = new DrawingVisual();
        var footer = new DrawingVisual();

        #region Heading
        var heading = new Grid() { Width = oldPage.Size.Width - 2 * 96 };
        heading.RowDefinitions.Add(new RowDefinition());
        heading.RowDefinitions.Add(new RowDefinition());
        heading.ColumnDefinitions.Add(new ColumnDefinition());
        heading.ColumnDefinitions.Add(new ColumnDefinition());

        var t1 = new TextBlock() { Text = "Trade Report", FontSize = 24, FontWeight = FontWeights.Bold, HorizontalAlignment = HorizontalAlignment.Center };
        var t2 = new TextBlock() { Text = "Customer Code: " + code, FontWeight = FontWeights.SemiBold, HorizontalAlignment = HorizontalAlignment.Left };
        var t3 = new TextBlock() { Text = "Date: " + DateTime.Now.ToShortDateString(), FontWeight = FontWeights.SemiBold, HorizontalAlignment = HorizontalAlignment.Right };

        Grid.SetColumn(t1, 0); Grid.SetRow(t1, 0); Grid.SetColumnSpan(t1, 2);
        Grid.SetColumn(t2, 0); Grid.SetRow(t2, 1);
        Grid.SetColumn(t3, 1); Grid.SetRow(t3, 1);

        heading.Children.Add(t1);
        heading.Children.Add(t2);
        heading.Children.Add(t3);
        heading.Measure(new Size(oldPage.Size.Width, oldPage.Size.Height));
        heading.Arrange(new Rect(heading.DesiredSize));
        var headingSize = new Size() { Height = heading.ActualHeight, Width = heading.ActualWidth };

        #endregion

        #region TableHeader

        var tableHeader = new Grid() { Width = oldPage.Size.Width - 2 * 96 };
        var border = new Border()
        {
            Background = new SolidColorBrush(Colors.LightGray),
            BorderBrush = new SolidColorBrush(Colors.Black),
            BorderThickness = new Thickness(0, 1, 0, 1),
            Child = tableHeader
        };

        for (int i = 0; i < headers.Length; i++)
        {
            tableHeader.ColumnDefinitions.Add(new ColumnDefinition());
            var head = new TextBlock() { Text = headers[i], FontWeight = FontWeights.Bold };

            if(i > 2)
            {
                tableHeader.ColumnDefinitions[i].Width = new GridLength(138);
                head.HorizontalAlignment = HorizontalAlignment.Right;
            }
            else
            {
                tableHeader.ColumnDefinitions[i].Width = new GridLength(70);
                head.HorizontalAlignment = HorizontalAlignment.Center;
            }

            Grid.SetColumn(head, i);
            tableHeader.Children.Add(head);
        }

        border.Measure(new Size(oldPage.Size.Width, oldPage.Size.Height));
        border.Arrange(new Rect(border.DesiredSize));
        var borderSize = new Size() { Height = border.ActualHeight, Width = border.ActualWidth };
        #endregion

        using (var dc = header.RenderOpen())
        {
            dc.DrawRectangle(new VisualBrush(heading), null, new Rect(new Point(96, 96), headingSize));
            dc.DrawRectangle(new VisualBrush(border), null, new Rect(new Point(96, 96 * 1.55), borderSize));
        }

        using(var dc = footer.RenderOpen())
        {
            var text = new TextBlock() { Text = "Page: " + (pageNumber + 1) };
            text.Measure(new Size(oldPage.Size.Width, oldPage.Size.Height));
            text.Arrange(new Rect(text.DesiredSize));
            var texSize = new Size() { Height = text.ActualHeight, Width = text.ActualWidth };
            dc.DrawRectangle(new VisualBrush(text), null, new Rect(oldPage.Size.Width - 96, oldPage.Size.Height - 96, texSize.Width, texSize.Height));
        }

        visual.Children.Add(header);
        visual.Children.Add(oldPage.Visual);
        visual.Children.Add(footer);

        return new DocumentPage(visual);
    }
}

it repeats the header and creates footer and in my PrintDoc function I only generate rows and set background for every other row from my List :

void PrintDoc(object obj)
{
    doc = new FlowDocument();
    doc.PageWidth = 96 * 8.5;
    doc.PageHeight = 96 * 11.7;
    doc.PagePadding = new Thickness(96, 96 * 1.7, 96, 96 * 1.1);

    var table = new Table();
    table.CellSpacing = 0;

    for (int i = 0; i < 6; i++)
    {
        var column = new TableColumn();
        if (i < 3) column.Width = new GridLength(70);
        else column.Width = new GridLength(138);
        table.Columns.Add(column);
    }

    var rowNum = 1;
    foreach (var item in Trade)
    {
        var rowGroup = new TableRowGroup();
        var row = new TableRow();

        row.Cells.Add(new TableCell(new Paragraph(new Run(item.TransNo.ToString()))) { TextAlignment = TextAlignment.Center});
        row.Cells.Add(new TableCell(new Paragraph(new Run(item.OrderNo.ToString()))) { TextAlignment = TextAlignment.Center});
        row.Cells.Add(new TableCell(new Paragraph(new Run(item.Type))) { TextAlignment = TextAlignment.Center});
        row.Cells.Add(new TableCell(new Paragraph(new Run(item.Price.ToString("N2")))) { TextAlignment = TextAlignment.Right});
        row.Cells.Add(new TableCell(new Paragraph(new Run(item.Quantity.ToString("N0")))) { TextAlignment = TextAlignment.Right});
        row.Cells.Add(new TableCell(new Paragraph(new Run(item.ValueTraded.ToString("N2")))) { TextAlignment = TextAlignment.Right});

        if (rowNum % 2 == 0) row.Background = new SolidColorBrush(Colors.LightGray);

        rowGroup.Rows.Add(row);
        table.RowGroups.Add(rowGroup);
        rowNum++;
    }
    doc.Blocks.Add(table);

    PrintDialog dialog = new PrintDialog();
    dialog.CurrentPageEnabled = true;
    dialog.UserPageRangeEnabled = true;
    if (dialog.ShowDialog() == true)
    {
        var paginator = new FlowPaginator(doc, CustomerCode);
        dialog.PrintDocument(paginator, "");
    }
}

Much simpler than what I'd thought, beautiful!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM