/* i-net software provides programming examples for illustration only, without warranty either expressed or implied, including, but not limited to, the implied warranties of merchantability and/or fitness for a particular purpose. This programming example assumes that you are familiar with the programming language being demonstrated and the tools used to create and debug procedures. i-net software support professionals can help explain the functionality of a particular procedure, but they will not modify these examples to provide added functionality or construct procedures to meet your specific needs. © i-net software 1998-2013 */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; using System.Drawing; using Inet.Viewer.Data; namespace Inet.Viewer.WinForms { /// /// Manage the background threads. /// internal static class ThreadManager { /// /// Add InvokeIfRequired to the Control /// /// Control for the thread context /// A delegate that contains a method to be called in the control's thread context. internal static void InvokeIfRequired(this Control control, MethodInvoker action) { if (control.InvokeRequired) { control.Invoke(new Action(delegate { try { action(); } catch (Exception e) { ViewerUtils.Debug(e.ToString()); throw; } })); } else { action(); } } /// /// Callback for a call of RequestPageData. /// /// the image of the page /// links of the page /// text blocks of the page /// the used painer instance internal delegate void SetImage(Image img, IList links, IList textLayouts, Graphics2DPainter painter); /// /// Helper class for the states of a call of RequestPageData. /// private class PageDataRequest { private Control control; private ReportDataCache data; private int page; private bool refresh; private PageLoader loader; private SetImage method; /// /// Create a new instance. /// /// Control for the thread context /// the data /// the page number which should be load /// true, if it is a refesh /// a loader for the page data /// the callback internal PageDataRequest(Control control, ReportDataCache data, int page, bool refresh, PageLoader loader, SetImage method) { this.control = control; this.data = data; this.page = page; this.refresh = refresh; this.loader = loader; this.method = method; } /// /// Callback method executed by a thread pool thread. /// /// ignored internal void Run(object nothing) { Image img = null; IList links = null; IList texts = null; Graphics2DPainter painter = null; try { byte[] pageData = data.PageData(page, refresh); loader.PaintPage(pageData); painter = loader.Painter; img = painter.GraphicsImage; links = painter.Links; texts = painter.TextBlocks; if (img == null) { // rendering was canceled return; } if (control == null) { method(img, links, texts, painter); } else { control.InvokeIfRequired(() => method(img, links, texts, painter)); } } catch (Exception e) { if (control == null) { loader.Receiver.PageLoadFailure(e); } else { control.InvokeIfRequired(() => loader.Receiver.PageLoadFailure(e)); } } } } /// /// Request the page data asynchronous from the server or cache. /// Then callback SetPageCount on the thread that owns the control's underlying window handle. /// /// Control for the thread context /// the data /// the page number which should be load /// true, if it is a refesh /// a loader for the page data /// the callback internal static void RequestPageData(Control control, ReportDataCache data, int page, bool refresh, PageLoader loader, SetImage method) { PageDataRequest request = new PageDataRequest(control, data, page, refresh, loader, method); ThreadPool.QueueUserWorkItem(new WaitCallback(request.Run), null); } /// /// Callback for a call of RequestPageCount. /// /// The resulting page count. /// If there are any error occur. internal delegate void SetPageCount(int pageCount, Exception ex); /// /// Helper class for the states of a call of RequestPageCount. /// private class PageCountRequest { private Control control; private ReportDataCache data; private SetPageCount method; /// /// Create a new instance. /// /// Control for the thread context /// the data /// the callback internal PageCountRequest(Control control, ReportDataCache data, SetPageCount method) { this.control = control; this.data = data; this.method = method; } /// /// Callback method executed by a thread pool thread. /// /// ignored internal void Run(object nothing) { int count = -1; Exception ex = null; try { count = data.PageCount(); if (count == -1) { throw new ViewerException("Server error/cancel during page count request (returned -1)"); } } catch (Exception e) { ex = e; } control.InvokeIfRequired(() => method(count, ex)); } } /// /// Request the page count asynchronous from the server or cache. /// Then callback SetPageCount on the thread that owns the control's underlying window handle. /// /// Control for the thread context /// the data /// the callback internal static void RequestPageCount(Control control, ReportDataCache data, SetPageCount method) { PageCountRequest request = new PageCountRequest(control, data, method); ThreadPool.QueueUserWorkItem(new WaitCallback(request.Run), null); } /// /// Callback for a call of RequestPageLimitExceed. /// /// The resulting flag. /// If there are any error occur. internal delegate void SetPageLimitExceeded(bool exceeded, Exception ex); /// /// Helper class for the states of a call of RequestPageLimitExceed. /// private class PageLimitExceedRequest { private Control control; private ReportDataCache data; private SetPageLimitExceeded method; /// /// Create a new instance. /// /// Control for the thread context /// the data /// the callback internal PageLimitExceedRequest(Control control, ReportDataCache data, SetPageLimitExceeded method) { this.control = control; this.data = data; this.method = method; } /// /// Callback method executed by a thread pool thread. /// /// ignored internal void Run(object nothing) { bool exceeded = false; Exception ex = null; try { exceeded = data.IsPageLimmitExcced(); } catch (Exception e) { ex = e; } control.InvokeIfRequired(() => method(exceeded, ex)); } } /// /// Request the page limit flag asynchronous from the server or cache. /// Then callback SetPageCount on the thread that owns the control's underlying window handle. /// /// Control for the thread context /// the data /// the callback internal static void RequestPageLimitExceed(Control control, ReportDataCache data, SetPageLimitExceeded method) { PageLimitExceedRequest request = new PageLimitExceedRequest(control, data, method); ThreadPool.QueueUserWorkItem(new WaitCallback(request.Run), null); } /// /// Callback for a call of RequestGroupTree. /// /// The resulting nodes. /// If there are any error occur. internal delegate void SetGroupTree(GroupTreeNode[] nodes, Exception ex); /// /// Helper class for the states of a call of RequestGroupTree. /// private class GroupTreeRequest { private Control control; private ReportDataCache data; private SetGroupTree method; /// /// Create a new instance. /// /// Control for the thread context /// the data /// the callback internal GroupTreeRequest(Control control, ReportDataCache data, SetGroupTree method) { this.control = control; this.data = data; this.method = method; } /// /// Callback method executed by a thread pool thread. /// /// ignored internal void Run(object nothing) { GroupTreeNode[] nodes = null; Exception ex = null; try { byte[] groupTreeData = data.GetGroupTree(); GroupLoader loader = new GroupLoader(); loader.Data = groupTreeData; loader.LoadData(); nodes = loader.GroupTreeNodes; } catch (Exception e) { ex = e; } control.InvokeIfRequired(() => method(nodes, ex)); } } /// /// Request the group tree asynchronous from the server or cache. /// Then callback SetPageCount on the thread that owns the control's underlying window handle. /// /// Control for the thread context /// the data /// the callback internal static void RequestGroupTree(Control control, ReportDataCache data, SetGroupTree method) { GroupTreeRequest request = new GroupTreeRequest(control, data, method); ThreadPool.QueueUserWorkItem(new WaitCallback(request.Run), null); } /// /// Sends asynchronously a ping request to reset the server cache timeout. /// /// internal static void RequestPing(IRenderData data) { ThreadPool.QueueUserWorkItem(new WaitCallback(delegate { try { data.Ping(); } catch (Exception) { // ignore } }), null); } } }