1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
|
public class Report : FrameworkElement
{
public DataTemplate PageHeaderTemplate
{
get { return (DataTemplate)GetValue(PageHeaderTemplateProperty); }
set { SetValue(PageHeaderTemplateProperty, value); }
}
public static readonly DependencyProperty PageHeaderTemplateProperty =
DependencyProperty.Register("PageHeaderTemplate", typeof(DataTemplate), typeof(Report), new PropertyMetadata(null));
public DataTemplate PageFooterTemplate
{
get { return (DataTemplate)GetValue(PageFooterTemplateProperty); }
set { SetValue(PageFooterTemplateProperty, value); }
}
public static readonly DependencyProperty PageFooterTemplateProperty =
DependencyProperty.Register("PageFooterTemplate", typeof(DataTemplate), typeof(Report), new PropertyMetadata(null));
public DataTemplate ItemTemplate
{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
public static readonly DependencyProperty ItemTemplateProperty =
DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(Report), new PropertyMetadata(null));
public DataTemplate ReportFooterTemplate
{
get { return (DataTemplate)GetValue(ReportFooterTemplateProperty); }
set { SetValue(ReportFooterTemplateProperty, value); }
}
public static readonly DependencyProperty ReportFooterTemplateProperty =
DependencyProperty.Register("ReportFooterTemplate", typeof(DataTemplate), typeof(Report), new PropertyMetadata(null));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(Report), new PropertyMetadata(null));
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(Report), new PropertyMetadata("Report"));
//#region Columns Visibility
public Visibility DateVisibility
{
get { return (Visibility)GetValue(DateVisibilityProperty); }
set { SetValue(DateVisibilityProperty, value); }
}
public static readonly DependencyProperty DateVisibilityProperty =
DependencyProperty.Register("DateVisibility", typeof(Visibility), typeof(Report), new PropertyMetadata(null));
public int CurrentPageNumber
{
get { return (int)GetValue(CurrentPageNumberProperty); }
private set { SetValue(CurrentPageNumberProperty, value); }
}
public static readonly DependencyProperty CurrentPageNumberProperty =
DependencyProperty.Register("CurrentPageNumber", typeof(int), typeof(Report), new PropertyMetadata(0));
public int TotalPageCount
{
get { return (int)GetValue(TotalPageCountProperty); }
private set { SetValue(TotalPageCountProperty, value); }
}
public static readonly DependencyProperty TotalPageCountProperty =
DependencyProperty.Register("TotalPageCount", typeof(int), typeof(Report), new PropertyMetadata(0));
private PrintDocument _printDocument = new PrintDocument();
public PrintDocument PrintDocument
{
get { return _printDocument; }
}
public event EventHandler EndPrint;
protected void OnEndPrint(EventArgs args)
{
if (EndPrint != null)
EndPrint(this, args);
}
public event EventHandler BeginPrint;
protected void OnBeginPrint(EventArgs args)
{
if (BeginPrint != null)
BeginPrint(this, args);
}
public event EventHandler EndBuildReport;
protected void OnEndBuildReport(EventArgs args)
{
if (EndBuildReport != null)
EndBuildReport(this, args);
}
public event EventHandler BeginBuildReport;
protected void OnBeginBuildReport(EventArgs args)
{
if (BeginBuildReport != null)
BeginBuildReport(this, args);
}
public event EventHandler EndBuildReportItem;
protected void OnEndBuildReportItem(EventArgs args)
{
if (EndBuildReportItem != null)
EndBuildReportItem(this, args);
}
public event EventHandler<PrintingEventArgs> BeginBuildReportItem;
protected void OnBeginBuildReportItem(PrintingEventArgs args)
{
if (BeginBuildReportItem != null)
BeginBuildReportItem(this, args);
}
public event EventHandler<PrintingEventArgs> BeginBuildReportFooter;
protected void OnBeginBuildReportFooter(PrintingEventArgs args)
{
if (BeginBuildReportFooter != null)
BeginBuildReportFooter(this, args);
}
private int _pageTreeIndex = 0;
private void PrintDocumentPrintPageHandler(object sender, PrintPageEventArgs e)
{
if (_pageTreeIndex == 0)
{
BuildReport(e.PrintableArea);
TotalPageCount = _pageTrees.Count;
CurrentPageNumber = 0;
}
if (_pageTrees.Count > 0)
{
CurrentPageNumber++;
e.PageVisual = _pageTrees[_pageTreeIndex];
}
e.HasMorePages = _pageTreeIndex < _pageTrees.Count - 1;
_pageTreeIndex++;
}
private void PrintDocumentBeginPrintHandler(object sender, BeginPrintEventArgs e)
{
OnBeginPrint(EventArgs.Empty);
}
private void PrintDocumentEndPrintHandler(object sender, EndPrintEventArgs e)
{
OnEndPrint(EventArgs.Empty);
// remove event handlers so we don't have any references hanging around
_printDocument.PrintPage -= PrintDocumentPrintPageHandler;
_printDocument.BeginPrint -= PrintDocumentBeginPrintHandler;
_printDocument.EndPrint -= PrintDocumentEndPrintHandler;
}
public void Print()
{
Print(null);
}
public void Print(PrinterFallbackSettings settings)
{
CurrentPageNumber = 0;
_pageTreeIndex = 0;
_printDocument.PrintPage += PrintDocumentPrintPageHandler;
_printDocument.BeginPrint += PrintDocumentBeginPrintHandler;
_printDocument.EndPrint += PrintDocumentEndPrintHandler;
if (settings != null)
_printDocument.Print(Title.Replace(" ", ""), settings);
else
_printDocument.Print(Title.Replace(" ", ""));
}
private List<UIElement> _pageTrees = new List<UIElement>();
// Pre-calculates pages. This allows for total page count
// as well as better handling of page breaks, and eventual
// inclusion of groups and whatnot. If this takes too long, though
// it'll exceed the timeout and make the printing fail in a
// sandboxed silverlight application. Alternative would be to make
// printing a two-step operation: First, build report, Second, user
// clicks button to do the actual printing. That approach
// introduces issues with data changing in-between the steps.
private void BuildReport(Size printableArea)
{
_pageTrees.Clear();
CurrentPageNumber = 0;
OnBeginBuildReport(EventArgs.Empty);
if (ItemsSource == null)
return;
IEnumerable reportItems = ItemsSource;
IEnumerator reportItemsEnumerator = reportItems.GetEnumerator();
reportItemsEnumerator.Reset();
StackPanel itemsPanel = null;
Grid pagePanel = null;
Size itemsPanelMaxSize = new Size();
// create first page
pagePanel = GetNewPage(printableArea, out itemsPanel, out itemsPanelMaxSize);
// add the items
while (reportItemsEnumerator.MoveNext())
{
object currentItem = reportItemsEnumerator.Current;
PrintingEventArgs args = new PrintingEventArgs();
args.DataContext = currentItem;
OnBeginBuildReportItem(args);
// create row. Set data context.
FrameworkElement row = ItemTemplate.LoadContent() as FrameworkElement;
row.DataContext = args.DataContext;
// ContentPresenter approach was tried to see if it helped resolve Run
// inlines with binding. No go.
//ContentPresenter row = new ContentPresenter();
//row.ContentTemplate = ItemTemplate;
//row.Content = currentItem;
row.Measure(printableArea);
// create a new page if we're out of room here
if (row.DesiredSize.Height + itemsPanel.DesiredSize.Height > itemsPanelMaxSize.Height)
{
pagePanel = GetNewPage(printableArea, out itemsPanel, out itemsPanelMaxSize);
}
itemsPanel.Children.Add(row);
itemsPanel.Measure(printableArea);
}
// create report footer. This goes at the very end of the report and typically
// includes totals and other summary information
if (ReportFooterTemplate != null)
{
PrintingEventArgs reportFooterEventArgs = new PrintingEventArgs();
reportFooterEventArgs.DataContext = this;
OnBeginBuildReportFooter(reportFooterEventArgs);
FrameworkElement reportFooter = ReportFooterTemplate.LoadContent() as FrameworkElement;
if (reportFooter != null)
{
reportFooter.DataContext = reportFooterEventArgs.DataContext;
reportFooter.Measure(printableArea);
// fit the footer into the report
if (reportFooter.DesiredSize.Height + itemsPanel.DesiredSize.Height > itemsPanelMaxSize.Height)
{
pagePanel = GetNewPage(printableArea, out itemsPanel, out itemsPanelMaxSize);
}
itemsPanel.Children.Add(reportFooter);
}
}
OnEndBuildReport(EventArgs.Empty);
}
private Grid GetNewPage(Size printableArea, out StackPanel itemsPanel, out Size itemsPanelMaxSize)
{
const int HeaderGridRowNumber = 0;
const int BodyGridRowNumber = 1;
const int FooterGridRowNumber = 2;
CurrentPageNumber++;
Grid pagePanel = new Grid();
RowDefinition headerRow = new RowDefinition();
headerRow.Height = GridLength.Auto;
pagePanel.Background = new SolidColorBrush { Color = Colors.White };
RowDefinition itemsRow = new RowDefinition();
itemsRow.Height = new GridLength(1, GridUnitType.Star);
RowDefinition footerRow = new RowDefinition();
footerRow.Height = GridLength.Auto;
pagePanel.RowDefinitions.Add(headerRow);
pagePanel.RowDefinitions.Add(itemsRow);
pagePanel.RowDefinitions.Add(footerRow);
// page header. Typically includes column headers and whatnot
double headerDesiredHeight = 0;
if (PageHeaderTemplate != null)
{
FrameworkElement header = PageHeaderTemplate.LoadContent() as FrameworkElement;
header.DataContext = this;
Grid.SetRow(header, HeaderGridRowNumber);
pagePanel.Children.Add(header);
header.Measure(new Size(printableArea.Width, printableArea.Height));
headerDesiredHeight = header.DesiredSize.Height;
}
// create body to fit in between
itemsPanel = new StackPanel();
itemsPanel.Orientation = Orientation.Vertical;
itemsPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
itemsPanel.VerticalAlignment = VerticalAlignment.Top;
itemsPanel.Background = new SolidColorBrush { Color = Colors.White };
Grid.SetRow(itemsPanel, BodyGridRowNumber);
pagePanel.Children.Add(itemsPanel);
// create page footer. Typically includes the page number
double footerDesiredHeight = 0;
if (PageFooterTemplate != null)
{
FrameworkElement footer = PageFooterTemplate.LoadContent() as FrameworkElement;
footer.DataContext = this;
Grid.SetRow(footer, FooterGridRowNumber);
pagePanel.Children.Add(footer);
footer.Measure(new Size(printableArea.Width, printableArea.Height));
footerDesiredHeight = footer.DesiredSize.Height;
}
itemsPanelMaxSize = new Size(printableArea.Width, printableArea.Height - footerDesiredHeight - headerDesiredHeight);
_pageTrees.Add(pagePanel);
return pagePanel;
}
} |
Partager