Report.PreviewExt.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. using FastReport.Engine;
  2. using FastReport.Forms;
  3. using FastReport.Preview;
  4. using FastReport.Utils;
  5. using System;
  6. using System.ComponentModel;
  7. using System.Drawing;
  8. using System.Drawing.Printing;
  9. using System.Threading.Tasks;
  10. using System.Windows.Forms;
  11. namespace FastReport
  12. {
  13. partial class Report
  14. {
  15. #region Private Fields
  16. private int tickCount;
  17. private EmailSettings emailSettings;
  18. private FastReport.Preview.PreviewControl preview;
  19. private BaseForm previewForm;
  20. private PrintSettings printSettings;
  21. private bool isPreviewing;
  22. #endregion Private Fields
  23. #region Public Properties
  24. /// <summary>
  25. /// Gets the email settings such as recipients, subject, message body.
  26. /// </summary>
  27. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  28. [SRCategory("Email")]
  29. public EmailSettings EmailSettings
  30. {
  31. get { return emailSettings; }
  32. }
  33. /// <summary>
  34. /// Gets or sets the report preview control.
  35. /// </summary>
  36. /// <remarks>
  37. /// Use this property to attach a custom preview to your report. To do this, place the PreviewControl
  38. /// control to your form and set the report's <b>Preview</b> property to this control.
  39. /// </remarks>
  40. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  41. public Preview.PreviewControl Preview
  42. {
  43. get { return preview; }
  44. set
  45. {
  46. preview = value;
  47. if (value != null)
  48. value.SetReport(this);
  49. }
  50. }
  51. /// <summary>
  52. /// Gets the print settings such as printer name, copies, pages to print etc.
  53. /// </summary>
  54. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  55. [SRCategory("Print")]
  56. public PrintSettings PrintSettings
  57. {
  58. get { return printSettings; }
  59. }
  60. /// <summary>
  61. ///
  62. /// </summary>
  63. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  64. public bool IsPreviewing
  65. {
  66. get { return isPreviewing; }
  67. }
  68. #endregion Public Properties
  69. #region Public Methods
  70. /// <summary>
  71. /// Prepares the report and prints it.
  72. /// </summary>
  73. public void Print()
  74. {
  75. if (Prepare())
  76. PrintPrepared();
  77. }
  78. /// <summary>
  79. /// Prints the report with the "Print" dialog.
  80. /// Report should be prepared using the <see cref="Prepare()"/> method.
  81. /// </summary>
  82. public void PrintPrepared()
  83. {
  84. if (PreparedPages != null)
  85. PreparedPages.Print();
  86. }
  87. /// <summary>
  88. /// Prints the report without the "Print" dialog.
  89. /// Report should be prepared using the <see cref="Prepare()"/> method.
  90. /// </summary>
  91. /// <param name="printerSettings">Printer-specific settings.</param>
  92. /// <example>
  93. /// Use the following code if you want to show the "Print" dialog, then print:
  94. /// <code>
  95. /// if (report.Prepare())
  96. /// {
  97. /// PrinterSettings printerSettings = null;
  98. /// if (report.ShowPrintDialog(out printerSettings))
  99. /// {
  100. /// report.PrintPrepared(printerSettings);
  101. /// }
  102. /// }
  103. /// </code>
  104. /// </example>
  105. public void PrintPrepared(PrinterSettings printerSettings)
  106. {
  107. if (PreparedPages != null)
  108. PreparedPages.Print(printerSettings, 1);
  109. }
  110. /// <summary>
  111. /// Prepares the report and shows it in the preview window.
  112. /// </summary>
  113. public void Show()
  114. {
  115. Show(true, null);
  116. }
  117. /// <summary>
  118. /// Prepares the report and shows it in the preview window.
  119. /// </summary>
  120. /// <param name="modal">A value that specifies whether the preview window should be modal.</param>
  121. public void Show(bool modal)
  122. {
  123. Show(modal, null);
  124. }
  125. /// <summary>
  126. /// Prepares the report and shows it in the preview window.
  127. /// </summary>
  128. /// <param name="modal">A value that specifies whether the preview window should be modal.</param>
  129. /// <param name="owner">The owner of the preview window.</param>
  130. public void Show(bool modal, IWin32Window owner)
  131. {
  132. if (Prepare())
  133. ShowPrepared(modal, null, owner);
  134. else if (Preview != null)
  135. {
  136. Preview.Clear();
  137. Preview.Refresh();
  138. }
  139. }
  140. /// <summary>
  141. /// Prepares the report and shows it in the preview window.
  142. /// </summary>
  143. /// <param name="mdiParent">The main MDI form which will be a parent for the preview window.</param>
  144. public void Show(Form mdiParent)
  145. {
  146. if (Prepare())
  147. ShowPrepared(false, mdiParent, null);
  148. else if (Preview != null)
  149. {
  150. Preview.Clear();
  151. Preview.Refresh();
  152. }
  153. }
  154. /// <summary>
  155. /// Previews the report. The report should be prepared using the <see cref="Prepare()"/> method.
  156. /// </summary>
  157. public void ShowPrepared()
  158. {
  159. ShowPrepared(true);
  160. }
  161. /// <summary>
  162. /// Previews the prepared report.
  163. /// </summary>
  164. /// <param name="modal">A value that specifies whether the preview window should be modal.</param>
  165. public void ShowPrepared(bool modal)
  166. {
  167. ShowPrepared(modal, null, null);
  168. }
  169. /// <summary>
  170. /// Previews the prepared report.
  171. /// </summary>
  172. /// <param name="modal">A value that specifies whether the preview window should be modal.</param>
  173. /// <param name="owner">The owner of the preview window.</param>
  174. public void ShowPrepared(bool modal, IWin32Window owner)
  175. {
  176. ShowPrepared(modal, null, owner);
  177. }
  178. /// <summary>
  179. /// Previews the prepared report.
  180. /// </summary>
  181. /// <param name="mdiParent">The main MDI form which will be a parent for the preview window.</param>
  182. public void ShowPrepared(Form mdiParent)
  183. {
  184. ShowPrepared(false, mdiParent, null);
  185. }
  186. /// <summary>
  187. /// Shows the "Print" dialog.
  188. /// </summary>
  189. /// <param name="printerSettings">Printer-specific settings.</param>
  190. /// <returns><b>true</b> if the dialog was closed by "Print" button.</returns>
  191. /// <example>
  192. /// Use the following code if you want to show the "Print" dialog, then print:
  193. /// <code>
  194. /// if (report.Prepare())
  195. /// {
  196. /// PrinterSettings printerSettings = null;
  197. /// if (report.ShowPrintDialog(out printerSettings))
  198. /// {
  199. /// report.PrintPrepared(printerSettings);
  200. /// }
  201. /// }
  202. /// </code>
  203. /// </example>
  204. public bool ShowPrintDialog(out PrinterSettings printerSettings)
  205. {
  206. printerSettings = null;
  207. using (PrinterSetupForm dialog = new PrinterSetupForm())
  208. {
  209. dialog.Report = this;
  210. dialog.PrintDialog = true;
  211. if (dialog.ShowDialog() != DialogResult.OK)
  212. return false;
  213. printerSettings = dialog.PrinterSettings;
  214. }
  215. return true;
  216. }
  217. #endregion Public Methods
  218. #region Async Prepare/Show methods
  219. /* proposed usage:
  220. try
  221. {
  222. if (AsyncPrepareStart()) // startup, compile, run dialogs. May throw a compiler exception
  223. AsyncPrepareRun(); // run report pages (may be run pseudo async way)
  224. }
  225. finally
  226. {
  227. AsyncPrepareFinish(); // cleanup
  228. }
  229. */
  230. internal async Task<bool> AsyncPrepareStart()
  231. {
  232. SetRunning(true);
  233. ClearPreparedPages();
  234. SetPreparedPages(new Preview.PreparedPages(this));
  235. engine = new ReportEngine(this);
  236. StartPerformanceCounter();
  237. Compile();
  238. Engine.RunPhase1();
  239. // WPF: dialogs should be run here, before we set up modal preview window (deadlock issue)
  240. return await Engine.RunDialogsAsync();
  241. }
  242. internal void AsyncPrepareRun()
  243. {
  244. Engine.RunPhase2(false, null);
  245. }
  246. internal void AsyncPrepareFinish()
  247. {
  248. Engine.RunFinished();
  249. StopPerformanceCounter();
  250. SetRunning(false);
  251. if (Config.ReportSettings.ShowPerformance)
  252. Preview?.ShowPerformance(String.Format(Res.Get("Messages,Performance"), tickCount));
  253. if (ReportInfo.SavePreviewPicture && PreparedPages.Count > 0)
  254. SavePreviewPicture();
  255. }
  256. /// <summary>
  257. /// Prepares the report and shows it in the provided PreviewControl (async way).
  258. /// </summary>
  259. /// <param name="preview">The preview control.</param>
  260. public async Task PrepareAsync(PreviewControl preview)
  261. {
  262. if (preview == null)
  263. throw new ArgumentNullException(nameof(preview));
  264. bool saveProgress = Config.ReportSettings.ShowProgress;
  265. Config.ReportSettings.ShowProgress = false;
  266. var saveButtons = preview.Buttons;
  267. bool finished = false;
  268. try
  269. {
  270. if (await AsyncPrepareStart()) // startup, compile, run dialogs. May throw a compiler exception
  271. {
  272. // setup preview control
  273. preview.SetAsyncReportRunning();
  274. preview.Buttons |= PreviewButtons.Close;
  275. Preview = preview;
  276. SetupPreviewControl();
  277. preview.AsyncReportStart();
  278. var tcs = new System.Threading.Tasks.TaskCompletionSource<bool>();
  279. var timer = new Timer() { Interval = 50 };
  280. timer.Tick += (s, args) =>
  281. {
  282. timer.Dispose();
  283. try
  284. {
  285. AsyncPrepareRun(); // run report pages (pseudo async way). May throw a runtime exception
  286. }
  287. finally
  288. {
  289. AsyncPrepareFinish(); // cleanup
  290. preview.AsyncReportFinish();
  291. finished = true;
  292. tcs.SetResult(true);
  293. }
  294. };
  295. timer.Start();
  296. Config.PreviewSettings.OnPreviewOpened(Preview);
  297. // wait for report to finish
  298. await tcs.Task;
  299. }
  300. }
  301. finally
  302. {
  303. if (!finished)
  304. AsyncPrepareFinish(); // cleanup
  305. Config.ReportSettings.ShowProgress = saveProgress;
  306. preview.Buttons = saveButtons;
  307. }
  308. }
  309. private async Task ShowAsync(bool modal, Form mdiParent, IWin32Window owner)
  310. {
  311. bool saveProgress = Config.ReportSettings.ShowProgress;
  312. Config.ReportSettings.ShowProgress = false;
  313. bool finished = false;
  314. try
  315. {
  316. if (await AsyncPrepareStart()) // startup, compile, run dialogs. May throw a compiler exception
  317. {
  318. // create preview form
  319. previewForm = CreatePreviewForm();
  320. previewForm.MdiParent = mdiParent;
  321. // setup preview control
  322. var preview = Preview;
  323. preview.SetAsyncReportRunning();
  324. preview.Buttons |= PreviewButtons.Close;
  325. SetupPreviewControl();
  326. preview.AsyncReportStart();
  327. previewForm.Shown += (sender, e) =>
  328. {
  329. var timer = new Timer() { Interval = 50 };
  330. timer.Tick += (s, args) =>
  331. {
  332. timer.Dispose();
  333. try
  334. {
  335. AsyncPrepareRun(); // run report pages (pseudo async way). May throw a runtime exception
  336. }
  337. finally
  338. {
  339. AsyncPrepareFinish(); // cleanup
  340. preview.AsyncReportFinish();
  341. finished = true;
  342. }
  343. };
  344. timer.Start();
  345. };
  346. #if AVALONIA
  347. await ShowPreviewFormAsync(modal, mdiParent, owner);
  348. #else
  349. ShowPreviewForm(modal, mdiParent, owner);
  350. #endif
  351. }
  352. }
  353. finally
  354. {
  355. if (!finished)
  356. AsyncPrepareFinish(); // cleanup
  357. Config.ReportSettings.ShowProgress = saveProgress;
  358. finished = true;
  359. }
  360. }
  361. /// <summary>
  362. /// Prepares the report and shows it in the preview window (async way).
  363. /// </summary>
  364. public async Task ShowAsync() => await ShowAsync(true, null);
  365. /// <summary>
  366. /// Prepares the report and shows it in the preview window (async way).
  367. /// </summary>
  368. /// <param name="modal">A value that specifies whether the preview window should be modal.</param>
  369. public async Task ShowAsync(bool modal) => await ShowAsync(modal, null);
  370. /// <summary>
  371. /// Prepares the report and shows it in the preview window (async way).
  372. /// </summary>
  373. /// <param name="modal">A value that specifies whether the preview window should be modal.</param>
  374. /// <param name="owner">The owner of the preview window.</param>
  375. public async Task ShowAsync(bool modal, IWin32Window owner) => await ShowAsync(modal, null, owner);
  376. /// <summary>
  377. /// Prepares the report and shows it in the preview window (async way).
  378. /// </summary>
  379. /// <param name="mdiParent">The main MDI form which will be a parent for the preview window.</param>
  380. public async Task ShowAsync(Form mdiParent) => await ShowAsync(false, mdiParent, null);
  381. #endregion
  382. #region Private Methods
  383. private void StartPerformanceCounter()
  384. {
  385. tickCount = Environment.TickCount;
  386. }
  387. private void StopPerformanceCounter()
  388. {
  389. tickCount = Environment.TickCount - tickCount;
  390. }
  391. private void ClearPreparedPages()
  392. {
  393. if (preview != null)
  394. preview.ClearTabsExceptFirst();
  395. else
  396. if (preparedPages != null)
  397. preparedPages.Clear();
  398. }
  399. private void DisposePreviewForm()
  400. {
  401. previewForm.Dispose();
  402. previewForm = null;
  403. preview = null;
  404. }
  405. private void OnClosePreview(object sender, FormClosedEventArgs e)
  406. {
  407. DisposePreviewForm();
  408. }
  409. private void SavePreviewPicture()
  410. {
  411. ReportPage page = PreparedPages.GetCachedPage(0);
  412. float pageWidth = page.WidthInPixels;
  413. float pageHeight = page.HeightInPixels;
  414. float ratio = ReportInfo.PreviewPictureRatio;
  415. ReportInfo.Picture = new Bitmap((int)Math.Round(pageWidth * ratio), (int)Math.Round(pageHeight * ratio));
  416. using (Graphics g = Graphics.FromImage(ReportInfo.Picture))
  417. {
  418. FRPaintEventArgs args = new FRPaintEventArgs(g, ratio, ratio, GraphicCache);
  419. page.Draw(args);
  420. }
  421. }
  422. private void ShowPrepared(bool modal, Form mdiParent, IWin32Window owner)
  423. {
  424. // create preview form
  425. if (Preview == null)
  426. {
  427. previewForm = CreatePreviewForm();
  428. }
  429. SetupPreviewControl();
  430. if (Config.ReportSettings.ShowPerformance)
  431. {
  432. try
  433. {
  434. // in case the format string is wrong, use try/catch
  435. Preview.ShowPerformance(String.Format(Res.Get("Messages,Performance"), tickCount));
  436. }
  437. catch
  438. {
  439. }
  440. }
  441. if (ReportInfo.SavePreviewPicture && PreparedPages.Count > 0)
  442. SavePreviewPicture();
  443. ShowPreviewForm(modal, mdiParent, owner);
  444. }
  445. private PreviewForm CreatePreviewForm()
  446. {
  447. var previewForm = new PreviewForm();
  448. previewForm.ShowInTaskbar = Config.PreviewSettings.ShowInTaskbar;
  449. if (Config.PreviewSettings.TopMost)
  450. previewForm.TopMost = true;
  451. previewForm.Icon = Config.PreviewSettings.Icon;
  452. if (String.IsNullOrEmpty(Config.PreviewSettings.Text))
  453. {
  454. previewForm.Text = String.IsNullOrEmpty(ReportInfo.Name) ? "" : ReportInfo.Name + " - ";
  455. previewForm.Text += Res.Get("Preview");
  456. }
  457. else
  458. previewForm.Text = Config.PreviewSettings.Text;
  459. Preview = previewForm.Preview;
  460. Preview.UIStyle = Config.UIStyle;
  461. Preview.FastScrolling = Config.PreviewSettings.FastScrolling;
  462. Preview.Buttons = Config.PreviewSettings.Buttons;
  463. Preview.SaveInitialDirectory = Config.PreviewSettings.SaveInitialDirectory;
  464. return previewForm;
  465. }
  466. private void ShowPreviewForm(bool modal, Form mdiParent, IWin32Window owner)
  467. {
  468. Config.PreviewSettings.OnPreviewOpened(Preview);
  469. isPreviewing = true;
  470. if (previewForm != null && !previewForm.Visible)
  471. {
  472. previewForm.MdiParent = mdiParent;
  473. if (modal)
  474. {
  475. previewForm.ShowDialog(owner);
  476. DisposePreviewForm();
  477. }
  478. else
  479. {
  480. previewForm.FormClosed += new FormClosedEventHandler(OnClosePreview);
  481. if (mdiParent == null)
  482. previewForm.Show(owner);
  483. else
  484. previewForm.Show();
  485. }
  486. isPreviewing = false;
  487. }
  488. }
  489. #if AVALONIA
  490. private async Task ShowPreviewFormAsync(bool modal, Form mdiParent, IWin32Window owner)
  491. {
  492. Config.PreviewSettings.OnPreviewOpened(Preview);
  493. isPreviewing = true;
  494. if (previewForm != null && !previewForm.Visible)
  495. {
  496. previewForm.MdiParent = mdiParent;
  497. if (modal)
  498. {
  499. await previewForm.ShowDialogAsync(owner);
  500. DisposePreviewForm();
  501. }
  502. else
  503. {
  504. previewForm.FormClosed += new FormClosedEventHandler(OnClosePreview);
  505. if (mdiParent == null)
  506. previewForm.Show(owner);
  507. else
  508. previewForm.Show();
  509. }
  510. isPreviewing = false;
  511. }
  512. }
  513. #endif
  514. internal void SetupPreviewControl()
  515. {
  516. Preview.ClearTabsExceptFirst();
  517. if (PreparedPages != null)
  518. Preview.AddPreviewTab(this, GetReportName, null, true);
  519. }
  520. #endregion Private Methods
  521. }
  522. }