/*
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);
}
}
}