【问题标题】:Printing Dynamic Usercontrol via document paginator in WPF : Datagrid is printed empty通过 WPF 中的文档分页器打印动态用户控件:Datagrid 打印为空
【发布时间】:2011-03-24 16:44:54
【问题描述】:

我正在尝试打印 wpf 文档。我正在使用 documentpaginator 进行分页,并使用用户控件来创建要打印的实际视觉效果。我的用户控件有几个文本框和一个绑定到数据对象的数据网格,这些数据对象在运行时传递给用户控件。

现在代码在打印到 XPS 文档时效果很好,但是当它打印到物理打印机时,我的数据网格打印为空,尽管其他文本框打印完美。

下面是分页器类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 打印机上按预期工作,但在物理打印机上却没有。

感谢阅读问题,

纳温

【问题讨论】:

    标签: .net wpf dynamic datagrid printing


    【解决方案1】:

    看看这个tutorial。埋在 cmets 中的是 DocumentPaginator,它是为打印 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
    }
    

    【讨论】:

      猜你喜欢
      • 2013-10-29
      • 2011-04-17
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 2015-08-07
      • 1970-01-01
      • 2023-04-09
      相关资源
      最近更新 更多