Nav*_*een 10 .net printing wpf datagrid dynamic
我正在尝试打印一个wpf文档.我正在使用documentpaginator进行分页,并使用用户控件来创建实际的可视化内容进行打印.我的用户控件具有很少的文本框和数据网格绑定到数据对象,这些数据对象在运行时传递给用户控件.
现在代码在打印到XPS文档时效果很好,但是当它打印到物理打印机时,我的数据网格打印为空,但其他文本框打印完美.
下面是paginator类GetPage方法的代码:
  SaleOrderPage page = new SaleOrderPage(order, pageNumber, controlSize);
        page.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        page.Arrange(new Rect(new Point(0, 0), PageSize));
        page.InitPrint();
        page.UpdateLayout();
        return new DocumentPage(page);
InitPrint方法正在初始化我的数据网格并将其绑定到数据源.这是InitPrint方法的代码.
 public void InitPrint() {
        var sales = ctx.SalesOrders.Where(so => so.Id.Equals(order.Id)).First().Sales.Skip(pageNumber * PageRows).Take(PageRows);
        var printData = sales.Select(x => new {
            Particulars = string.Format("{0} - {1}", x.Item.Brand.Name, x.Item.Shade.Name),
            Quantity = string.Format("{0} {1}", x.Quantity, x.Item.Brand.Unit.Symbol)
        }).ToList();
        dgSales.ItemsSource = printData;
        dgSalesCopy.ItemsSource = printData;
    }
我相信我在打印到实际打印机时缺少一些步骤,因为它按照预期的方式运行到XPS打印机而不是物理打印机.
感谢阅读问题,
纳文
看看这个教程。隐藏在注释中的是一个DocumentPaginator明确创建用于打印 a 的DataGrid。
public class DocPaginator : DocumentPaginator
{
    #region Fields
    private int _rows;
    private int _columns;
    private int _rowsPerPage;
    private int _columnsPerPage;
    private int _firstColumnWidth;
    private int _horizontalPageCount;
    private int _verticalPageCount;
    private System.Windows.Size _pageSize;        
    private DataGrid _dataGrid;
    private List<string> _columnsList;
    private bool _isFirstColumnLarger;
    private List<Dictionary<int, Pair<int, int>>> _columnSlotsList;
    private string _strTitle;
    private string _strComment;
    #endregion Fields
    #region Constructor
    public DocPaginator(DataGrid dataGrid, System.Windows.Size pageSize, List<string> columnsList, 
                            bool isFirstColumnLarger = false, string strTitle = null, string strComment = null)
    {
        _rows = dataGrid.Items.Count;
        _columns = dataGrid.Columns.Count;            
        _dataGrid = dataGrid;
        _columnsList = columnsList;
        _isFirstColumnLarger = isFirstColumnLarger;
        _strTitle = strTitle;
        _strComment = strComment;
        CalculateFirstColumnWidth();
        PageSize = pageSize;
        _horizontalPageCount = HorizontalPageCount;
        _verticalPageCount = VerticalPageCount;
        GenerateColumnSlots();
    }
    #endregion Constructor
    #region Public Methods
    public override DocumentPage GetPage(int pageNumber)
    {
        double pgNumber = Math.IEEERemainder(pageNumber, _verticalPageCount) >= 0 ?
                            Math.IEEERemainder(pageNumber, _verticalPageCount) :
                                Math.IEEERemainder(pageNumber, _verticalPageCount) + _verticalPageCount;
        int currentRow = Convert.ToInt32(_rowsPerPage * pgNumber);
        var page = new PageElement(currentRow, Math.Min(_rowsPerPage, _rows - currentRow), _dataGrid,
                                        _columnsList, _firstColumnWidth, _isFirstColumnLarger,
                                            GetColumnSlot(pageNumber), _strTitle, _strComment, GetPageNumber(pageNumber))
        {
            Width = PageSize.Width,
            Height = PageSize.Height,
        };
        page.Measure(PageSize);
        page.Arrange(new Rect(new System.Windows.Point(0, 0), PageSize));
        return new DocumentPage(page);
    }
    #endregion Public Methods
    #region Public Properties
    public override bool IsPageCountValid
    { get { return true; } }
    public override int PageCount
    { get { return _horizontalPageCount * _verticalPageCount; } }
    public override System.Windows.Size PageSize
    {
        get { return _pageSize; }
        set
        {
            _pageSize = value;
            _rowsPerPage = PageElement.RowsPerPage(PageSize.Height);
            _columnsPerPage = PageElement.ColumnsPerPage(PageSize.Width, _firstColumnWidth);
            //Can't print anything if you can't fit a row on a page
            Debug.Assert(_rowsPerPage > 0);
        }
    }
    public override IDocumentPaginatorSource Source
    { get { return null; } }
    public int HorizontalPageCount
    {
        get { return (int)Math.Ceiling((_columns - 1) / (double)_columnsPerPage); }
    }
    public int VerticalPageCount
    { 
        get { return (int)Math.Ceiling(_rows / (double)_rowsPerPage); } 
    }
    #endregion Public Properties
    #region Private Methods
    private void CalculateFirstColumnWidth()
    {
        int maxDataLen = 0;
        for (int i = 0; i < _dataGrid.Items.Count; i++)
        {
            List<Object> icol = (List<Object>)_dataGrid.Items[i];
            var largestDataItem = (from d in icol 
                                    select d != null ? d.ToString().Length : 0).Max();
            maxDataLen = maxDataLen < largestDataItem ? largestDataItem : maxDataLen;
        }
        string strDataLen = string.Join("a", new string[maxDataLen + 1]);
        _firstColumnWidth = PageElement.CalculateBitLength(strDataLen, 
                                            new Font("Tahoma", 8, System.Drawing.FontStyle.Regular, GraphicsUnit.Point));
    }
    private void GenerateColumnSlots()
    {
        _columnSlotsList = new List<Dictionary<int, Pair<int, int>>>();
        for (int i = 0; i < _horizontalPageCount; i++)
        {
            Dictionary<int, Pair<int, int>> columnSlot = new Dictionary<int, Pair<int, int>>();
            columnSlot.Add(1, new Pair<int, int>((_columnsPerPage * i) + 1,
                                                    Math.Min(_columnsPerPage * (i + 1), _columns - 1)));
            _columnSlotsList.Add(columnSlot);
        }
    }
    private Dictionary<int, Pair<int, int>> GetColumnSlot(int pageNumber)
    {
        for (int i = 0; i <= _columnSlotsList.Count; i++)
        {
            if (i == Math.Ceiling(Convert.ToDouble(pageNumber / _verticalPageCount)))
                return _columnSlotsList[i];
        }
        return new Dictionary<int, Pair<int, int>>();
    }
    private string GetPageNumber(int intPageNumber)
    {
        string strPageNumber = String.Empty;
        if (_horizontalPageCount == 1)
            strPageNumber = (intPageNumber + 1).ToString();
        else
        { }
        return strPageNumber;
    }
    #endregion Private Methods
}
#region Pair Class
public class Pair<TStart, TEnd>
{
    public Pair(TStart start, TEnd end)
    {
        Start = start;
        End = end;
    }
    public TStart Start { get; set; }
    public TEnd End { get; set; }
}
#endregion
And this is the enhanced version of PageElement:
public class PageElement : UserControl
{
    #region Constants
    private const int PAGE_MARGIN = 40;
    private const int HEADER_HEIGHT = 50;
    private const int LINE_HEIGHT = 20;
    private const int COLUMN_WIDTH = 60;
    private const int HEADER_CHR_WIDTH = 9;
    private const int HEADER_LINE_HEIGHT = 12;
    private const string EXCAPE_CHAR = "\r\n";
    private const string NOT_APPLICAPLE = "N/A";
    #endregion Constants
    #region Fields
    private int _currentRow;
    private int _rows;
    private DataGrid _dataGrid;
    private List<string> _columns;
    private int _firstColumnWidth;        
    private bool _isFirstColumnLarger;
    private static int _columnsPerPage;
    private Dictionary<int, Pair<int, int>> _columnSlot;
    private string _strTitle;
    private string _strComment;
    private string _strPageNumber;        
    #endregion Fields
    #region Constructor
    public PageElement(int currentRow, int rows, DataGrid dataGrid, List<string> columns,
                        int firstColumnWidth, bool isFirstColumnLarger, Dictionary<int, 
                            Pair<int, int>> columnSlot, string strTitle, string strComment, 
                            string strPageNumber)
    {
        Margin = new Thickness(PAGE_MARGIN);
        _currentRow = currentRow;
        _rows = rows;
        _dataGrid = dataGrid;
        _columns = columns;
        _firstColumnWidth = firstColumnWidth;
        _isFirstColumnLarger = isFirstColumnLarger;
        _columnSlot = columnSlot;
        _strTitle = strTitle;
        _strComment = strComment;
        _strPageNumber = strPageNumber;
    }
    #endregion Constructor
    #region Public Static Functions
    public static int RowsPerPage(double height)
    {
        //5 times Line Height deducted for: 1 for Title and Comments each; 2 for Page Number and 1 for Date
        return (int)Math.Floor((height - (2 * PAGE_MARGIN) - HEADER_HEIGHT - (5 * LINE_HEIGHT)) / LINE_HEIGHT);
    }
    public static int ColumnsPerPage(double width, int firstColumnWidth)
    {
        _columnsPerPage = (int)Math.Floor((width - (2 * PAGE_MARGIN) - firstColumnWidth) / COLUMN_WIDTH);
        return _columnsPerPage;
    }
    public static int CalculateBitLength(string strData, d.Font font)
    {
        using (d.Graphics graphics = d.Graphics.FromImage(new d.Bitmap(1, 1)))
        {
            d.SizeF dtsize = graphics.MeasureString(strData, font);
            return Convert.ToInt32(dtsize.Width);
        }  
    }
    #endregion Public Static Functions
    #region Private Functions
    private static FormattedText MakeText(string text, int fontSize)
    {
        return new FormattedText(text, CultureInfo.CurrentCulture,
            FlowDirection.LeftToRight, new Typeface("Tahoma"), fontSize, Brushes.Black);
    }
    #endregion Private Functions
    #region Protected Functions
    protected override void OnRender(DrawingContext dc)
    {
        Point curPoint = new Point(0, 0);
        int beginCounter = 0;
        double intYAxisTracker = 0;
        double TitleHeight = 0;
        //Print Title.
        if (_strTitle != null)
        {
            int intTitleLength = CalculateBitLength(_strTitle, new d.Font("Tahoma", 9, d.FontStyle.Regular));
            curPoint.X = ((Width - (2 * PAGE_MARGIN)) / 2) - (intTitleLength / 2);
            dc.DrawText(MakeText(_strTitle, 9), curPoint);
            curPoint.Y += LINE_HEIGHT;
            curPoint.X = 0;
        }
        //Print Comment.
        if (_strTitle != null)
        {
            int intCommentLength = CalculateBitLength(_strComment, new d.Font("Tahoma", 9, d.FontStyle.Regular));
            curPoint.X = ((Width - (2 * PAGE_MARGIN)) / 2) - (intCommentLength / 2);
            dc.DrawText(MakeText(_strComment, 9), curPoint);
            curPoint.Y += LINE_HEIGHT;
            curPoint.X = 0;
        }
        //Print current Date.
        int intDatLength = CalculateBitLength(String.Format("{0:MMMM dd, yyyy}", DateTime.Now), new d.Font("Tahoma", 9, d.FontStyle.Regular));
        curPoint.X = ((Width - (2 * PAGE_MARGIN)) / 2) - (intDatLength / 2);
        dc.DrawText(MakeText(String.Format("{0:MMMM dd, yyyy}", DateTime.Now), 9), curPoint);
        curPoint.Y += LINE_HEIGHT;
        curPoint.X = 0;
        TitleHeight = curPoint.Y;
        //Print First column of header row.
        dc.DrawText(MakeText(_columns[0], 9), curPoint);
        curPoint.X += _firstColumnWidth;
        beginCounter = _columnSlot[1].Start;
        //Print other columns of header row
        for (int i = beginCounter; i <= _columnSlot[1].End; i++)
        {
            //Remove unwanted characters
            _columns[i] = _columns[i].Replace(EXCAPE_CHAR, " ");
            if (_columns[i].Length > HEADER_CHR_WIDTH)
            {
                //Loop through to wrap the header text
                for (int k = 0; k < _columns[i].Length; k += HEADER_CHR_WIDTH)
                {
                    int subsLength = k > _columns[i].Length - HEADER_CHR_WIDTH ? _columns[i].Length - k : HEADER_CHR_WIDTH;
                    dc.DrawText(MakeText(_columns[i].Substring(k, subsLength), 9), curPoint);
                    curPoint.Y += HEADER_LINE_HEIGHT;
                }
            }
            else
                dc.DrawText(MakeText(_columns[i], 9), curPoint);
            //YAxisTracker keeps track of maximum lines used to print the headers.
            intYAxisTracker = intYAxisTracker < curPoint.Y ? curPoint.Y : intYAxisTracker;
            curPoint.X += COLUMN_WIDTH;
            curPoint.Y = TitleHeight;
        }
        //Reset X and Y pointers
        curPoint.X = 0;
        curPoint.Y += intYAxisTracker - TitleHeight;
        //Draw a solid line
        dc.DrawRectangle(Brushes.Black, null, new Rect(curPoint, new Size(Width, 2)));
        curPoint.Y += HEADER_HEIGHT - (2 * LINE_HEIGHT);
        //Loop through each collection in dataGrid to print the data
        for (int i = _currentRow; i < _currentRow + _rows; i++)
        {
            List<Object> icol = (List<Object>)_dataGrid.Items[i];
            //Print first column data
            dc.DrawText(MakeText(icol[0].ToString(), 10), curPoint);
            curPoint.X += _firstColumnWidth;
            beginCounter = _columnSlot[1].Start;
            //Loop through items in the collection; Loop only the items for currect column slot.
            for (int j = beginCounter; j <= _columnSlot[1].End; j++)
            {
                dc.DrawText(MakeText(icol[j] == null ? NOT_APPLICAPLE : icol[j].ToString(), 10), curPoint);
                curPoint.X += COLUMN_WIDTH;
            }
            curPoint.Y += LINE_HEIGHT;
            curPoint.X = 0;
        }
        //Print Page numbers
        curPoint.Y = Height - (2 * PAGE_MARGIN) - LINE_HEIGHT;
        curPoint.X = Width - (2 * PAGE_MARGIN) - COLUMN_WIDTH;
        dc.DrawText(MakeText(_strPageNumber, 9), curPoint);
    }
    #endregion Protected Functions
}