在Winform中如果所有邏輯都在UI線程執行的話UI很容易就會被卡住轉圈未響應。爲了避免界面卡死,對於費時的操作需要用線程執行。但是有一種情況是我有很多操作都要用線程後臺執行來避免卡界面,但是我又不想多個線程調用無序,要求多個線程調用方法順序執行,來打的UI的順序執行和後臺線程的順序執行。這種情況對多個線程調用的進度管理就成了問題。爲了滿足這種Winform經常需要的情況,開發了線程管理類,後臺管理一個執行隊列,只持有一個線程來執行隊列裏的任務,既滿足了不卡UI的要求,又滿足後臺執行有序的要求。
實現類
///作者:張聯珠
///日期:2014-03-01
///[email protected]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Forms;
namespace LISMonitor
{
#region 異步工具調用前初始化的委託
/// <summary>
/// 初始化異步工具的委託
/// </summary>
/// <param name="backGroundWorker">BackgroundWorker</param>
public delegate void InitAsyUtil(BackgroundWorker backGroundWorker);
#endregion
#region 單線程時的後臺執行者
///<summary NoteObject="Class">
/// [功能描述:內部的後臺工作對象,如果要使後臺有序,幾個工具類都把任務交給該對象] <para/>
/// [創建者:張聯珠] <para/>
/// [創建時間:2014年4月11日] <para/>
///<說明>
/// [說明:修改原工具類
/// 使用說明:後臺操作方法不要訪問UI資源]<para/>
///</說明>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///</summary>
public static class InnerBackGroundWorker
{
/// <summary>
/// 私有的靜態工作對象
/// </summary>
private static BackgroundWorker SelfBackgroundWorker = new BackgroundWorker();
/// <summary>
/// 後臺隊列
/// </summary>
private static Queue<object[]> WaiteQueue = new Queue<object[]>();
/// <summary>
/// 調用鎖
/// </summary>
public static object Lock = new object();
/// <summary>
/// 運行一個任務,如果線程正忙,任務進入等待
/// </summary>
/// <param name="objs"></param>
public static void RunWorkerAsync(object [] objs)
{
lock (WaiteQueue)
{
//如果後臺正忙,進入隊列等待
if (SelfBackgroundWorker.IsBusy || WaiteQueue.Count > 0)
{
WaiteQueue.Enqueue(objs);
}
else
{
InitAsyUtil initAsyUitil = objs[4] as InitAsyUtil;
SelfBackgroundWorker = new BackgroundWorker();
initAsyUitil(SelfBackgroundWorker);
SelfBackgroundWorker.RunWorkerAsync(objs);
}
}
}
/// <summary>
/// 運行任務結束時執行,如果隊列沒有等待的任務,什麼也不做,否則執行下一條任務
/// </summary>
/// <param name="objs"></param>
public static void RunWorkerAsync()
{
lock (WaiteQueue)
{
//如果隊列中有等待
if (!SelfBackgroundWorker.IsBusy && WaiteQueue.Count > 0)
{
object[] objs = null;
objs = WaiteQueue.Dequeue();
SelfBackgroundWorker = new BackgroundWorker();
InitAsyUtil initAsyUitil = objs[4] as InitAsyUtil;
initAsyUitil(SelfBackgroundWorker);
SelfBackgroundWorker.RunWorkerAsync(objs);
}
}
}
}
#endregion
#region 帶返回類型的異步工具
///<summary NoteObject="Class">
/// [功能描述:管理的異步工具類] <para/>
/// [創建者:張聯珠] <para/>
/// [創建時間:2014年4月11日] <para/>
///<說明>
/// [說明:修改原工具類
/// 使用說明:後臺操作方法不要訪問UI資源]<para/>
///</說明>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///</summary>
public static class ManagedAsyncUtils<TResult>
{
/// <summary>
/// 私有的靜態工作對象
/// </summary>
private static BackgroundWorker SelfBackgroundWorker = null;
/// <summary>
/// 使用前出師化異步工具
/// </summary>
private static void InitUtil(BackgroundWorker backGroundWorker)
{
SelfBackgroundWorker = backGroundWorker;
SelfBackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
SelfBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
}
/// <summary>
/// 異步調用
/// </summary>
/// <param name="invokeCompleted">回調方法委託()回調的方法可以不是公有的,因爲使用委託了</param>
/// <param name="businessObject">調用目標對象實例(後臺方法所在類的對象)</param>
/// <param name="methodName">後臺執行的方法名稱(要申明成公有,應爲內部通過反射來訪問,不是公有的話會訪問不到。該操作方法不要訪問UI資源,在回調方法裏訪問)</param>
/// <param name="args">後臺執行方法需要的參數(和參數順序一樣的object數組)</param>
/// <param name="isSelfAsy">是否單獨一個異步</param>
public static void Invoke(Action<TResult, Exception> invokeCompleted, object businessObject,
string methodName, object[] args,bool isSelfAsy=false)
{
if (!isSelfAsy)
{
lock (InnerBackGroundWorker.Lock)
{
InnerBackGroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), isSelfAsy });
}
}
else
{
InitUtil(new BackgroundWorker());
SelfBackgroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), isSelfAsy });
}
}
/// <summary>
/// BackgroundWorker的後臺方法
/// </summary>
/// <param name="sender">事件發送者</param>
/// <param name="e">參數</param>
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//獲得參數數組
var arguments = e.Argument as object[];
//獲得回調方法
var completeMethod = arguments[0];
//獲得業務實體
var businessObject = arguments[1];
//獲得方法名
var methodName = arguments[2] as string;
//獲得參數
var args = arguments[3] as object[];
//存放結果
object result = null;
//存放異常
Exception ex = null;
try
{
//參數類型集合
List<Type> lstArgType = new List<Type>();
//把所有參數的類型填入集合
if (args != null && args.Length > 0)
{
for (int i = 0; i < args.Length; i++)
{
lstArgType.Add(args[i].GetType());
}
}
//獲得方法
var method = GetTarMethod(businessObject.GetType(), methodName, lstArgType.ToArray());
//如果沒找到該方法,直接執行該業務實體的方法
if (method == null)
{
//執行,並把結果賦給結果對象
result = businessObject.GetType().GetMethod(methodName, lstArgType.ToArray()).Invoke(businessObject, args);
}
//如果找到了方法,則通過接口調方法
else
{
result = method.Invoke(businessObject, args);
}
}
catch (Exception exThread)
{
ex = exThread;
}
//結果由參數帶回
e.Result = new object[] { result, completeMethod, ex, arguments[5] };
}
/// <summary>
/// 回調方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var results = e.Result as object[];
//取出結果
var result = results[0];
Exception ex = null;
//如果結果帶出的異常不爲空
if (results[2] != null)
{
var exThread = results[2] as Exception;
//如果內部異常不爲空,則取內部異常
if (exThread.InnerException != null)
{
ex = exThread.InnerException;
}
//否則直接取總異常
else
{
ex = exThread;
}
}
try
{
//取出回調委託
Action<TResult, Exception> method = results[1] as Action<TResult, Exception>;
//如果返回結果爲空,傳該類型的默認值
if (result == null)
{
method(default(TResult), ex);
}
//否則傳帶出的結果
else
{
method((TResult)result, ex);
}
}
//應對回調時回調對象已被銷燬
catch (Exception exc)
{
//把除了訪問已釋放的資源異常吃掉外,其他異常拋出,方便調試
if (!(exc is ObjectDisposedException))
{
throw exc;
}
}
finally
{
//及時清除引用,防止以後錯誤調用的干擾
SelfBackgroundWorker = null;
if(!((bool)results[3]))
{
InnerBackGroundWorker.RunWorkerAsync();
}
}
}
/// <summary>
/// 獲得目標方法
/// </summary>
/// <param name="svcType">方法所在類型</param>
/// <param name="methodName">方法名</param>
/// <param name="argTypes">參數類型集合</param>
/// <returns>方法信息</returns>
private static MethodInfo GetTarMethod(Type svcType, string methodName, Type[] argTypes)
{
//獲取由當前實體所實現的接口集合
foreach (var item in svcType.GetInterfaces())
{
//通過名稱和類型找方法
var method = item.GetMethod(methodName, argTypes);
//找到方法就返回
if (method != null)
{
return method;
}
}
return null;
}
}
#endregion
#region 不帶返回類型的異步工具
///<summary NoteObject="Class">
/// [功能描述:管理的異步工具類] <para/>
/// [創建者:張聯珠] <para/>
/// [創建時間:2014年4月11日] <para/>
///<說明>
/// [說明:修改原工具類
/// 使用說明:後臺操作方法不要訪問UI資源]<para/>
///</說明>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///</summary>
public static class ManagedAsyncUtils
{
/// <summary>
/// 私有的靜態工作對象
/// </summary>
private static BackgroundWorker SelfBackgroundWorker = null;
/// <summary>
/// 使用前初始化異步工具
/// </summary>
public static void InitUtil(BackgroundWorker backGroundWorker)
{
SelfBackgroundWorker = backGroundWorker;
SelfBackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
SelfBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
}
/// <summary>
/// 異步調用
/// </summary>
/// <param name="invokeCompleted">回調方法委託()回調的方法可以不是公有的,因爲使用委託了</param>
/// <param name="businessObject">調用目標對象實例(後臺方法所在類的對象)</param>
/// <param name="methodName">後臺執行的方法名稱(要申明成公有,應爲內部通過反射來訪問,不是公有的話會訪問不到。該操作方法不要訪問UI資源,在回調方法裏訪問)</param>
/// <param name="args">後臺執行方法需要的參數(和參數順序一樣的object數組)</param>
/// <param name="isSelfAsy">是否單獨一個異步</param>
public static void Invoke(Action<Exception> invokeCompleted, object businessObject,
string methodName,object[] args,bool isSelfAsy=false)
{
if (!isSelfAsy)
{
lock (InnerBackGroundWorker.Lock)
{
InnerBackGroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), isSelfAsy });
}
}
else
{
InitUtil(new BackgroundWorker());
SelfBackgroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), isSelfAsy });
}
}
/// <summary>
/// 後臺工作方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//提出方法參數
var arguments = e.Argument as object[];
//提出回調委託
var completeMethod = arguments[0];
//提出調用方法的對象
var businessObject = arguments[1];
//提出調用方法的名稱
var methodName = arguments[2] as string;
//提出調用方法的參數
var args = arguments[3] as object[];
//異常
Exception ex = null;
try
{
//存所有的參數類型
List<Type> lstArgType = new List<Type>();
if (args != null && args.Length > 0)
{
for (int i = 0; i < args.Length; i++)
{
lstArgType.Add(args[i].GetType());
}
}
//獲得調用方法
var method = GetTarMethod(businessObject.GetType(), methodName, lstArgType.ToArray());
if (method == null)
{
businessObject.GetType().GetMethod(methodName, lstArgType.ToArray()).Invoke(businessObject, args);
}
else
{
method.Invoke(businessObject, args);
}
}
catch (Exception exThread)
{
ex = exThread;
}
//結果由參數帶回
e.Result = new object[] { completeMethod, ex, arguments[5] };
}
/// <summary>
/// 獲得目標方法
/// </summary>
/// <param name="svcType">方法所在類型</param>
/// <param name="methodName">方法名</param>
/// <param name="argTypes">參數類型集合</param>
/// <returns>方法信息</returns>
private static MethodInfo GetTarMethod(Type svcType, string methodName, Type[] argTypes)
{
foreach (var item in svcType.GetInterfaces())
{
var method = item.GetMethod(methodName, argTypes);
if (method != null)
{
return method;
}
}
return null;
}
/// <summary>
/// 回調方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//取出結果
var results = e.Result as object[];
try
{
//取出回調方法
var method = results[0] as Action<Exception>;
if (results[1] != null)
{
var exThread = results[1] as Exception;
if (exThread.InnerException != null)
{
method(exThread.InnerException);
}
else
{
method(exThread);
}
}
else
{
method(null);
}
}
//應對回調時回調對象已被銷燬
catch (Exception exc)
{
//把除了訪問已釋放的資源異常吃掉外,其他異常拋出,方便調試
if (!(exc is ObjectDisposedException))
{
throw exc;
}
}
finally
{
//及時清除引用,防止以後錯誤調用的干擾
SelfBackgroundWorker = null;
if (!((bool)results[2]))
{
InnerBackGroundWorker.RunWorkerAsync();
}
}
}
}
#endregion
#region 帶返回類型的異步工具-含報告
///<summary NoteObject="Class">
/// [功能描述:管理的帶報告帶返回值的異步工具類,對於調用異步時使用單獨線程的操作就千萬不要調用Report方法,因爲單獨線程已經不處於託管環境了,此時調Report會干擾託管的線程] <para/>
/// [創建者:張聯珠] <para/>
/// [創建時間:2014年4月11日] <para/>
///<說明>
/// [說明:修改原工具類
/// 使用說明:後臺操作方法不要訪問UI資源]<para/>
///</說明>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///</summary>
public static class ManagedAsyncUtilsWithReport<TResult, TReport>
{
#region 字段
/// <summary>
/// 私有的靜態工作對象
/// </summary>
private static BackgroundWorker SelfBackgroundWorker = null;
/// <summary>
/// 通知回調
/// </summary>
private static Action<TReport, Exception> Reports;
#endregion
#region 構造函數
/// <summary>
/// 使用前初始化異步工具
/// </summary>
public static void InitUtil(BackgroundWorker backGroundWorker)
{
SelfBackgroundWorker = backGroundWorker;
SelfBackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
SelfBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
SelfBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
//支持報告進度
SelfBackgroundWorker.WorkerReportsProgress = true;
}
#endregion
#region 對外提供的方法
/// <summary>
/// 異步調用
/// </summary>
/// <param name="invokeCompleted">回調方法委託()回調的方法可以不是公有的,因爲使用委託了</param>
/// <param name="reportChanged">通知改變的回調方法委託(該參數可以爲空,爲空就不通知改變,如果傳入該參數不爲空,可以調用Report方法來反信息)回調的方法可以不是公有的,因爲使用委託了</param>
/// <param name="businessObject">調用目標對象實例(後臺方法所在類的對象)</param>
/// <param name="methodName">後臺執行的方法名稱(要申明成公有,應爲內部通過反射來訪問,不是公有的話會訪問不到。該操作方法不要訪問UI資源,在回調方法裏訪問)</param>
/// <param name="args">後臺執行方法需要的參數(和參數順序一樣的object數組)</param>
/// <param name="isSelfAsy">是否單獨一個異步</param>
public static void Invoke(Action<TResult, Exception> invokeCompleted, Action<TReport, Exception> reportChanged, object businessObject,
string methodName, object[] args, bool isSelfAsy = false)
{
if (!isSelfAsy)
{
lock (InnerBackGroundWorker.Lock)
{
InnerBackGroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), reportChanged, isSelfAsy });
}
}
else
{
InitUtil(new BackgroundWorker());
SelfBackgroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil), reportChanged, isSelfAsy });
}
}
/// <summary>
/// 報告事件
/// </summary>
/// <param name="reportInfo">報告內容</param>
/// <param name="ex">報告異常</param>
public static void Report(TReport reportInfo, Exception ex)
{
object[] args = new object[] { reportInfo, ex };
SelfBackgroundWorker.ReportProgress(0, args);
}
#endregion
#region 內部方法
/// <summary>
/// BackgroundWorker的後臺方法
/// </summary>
/// <param name="sender">事件發送者</param>
/// <param name="e">參數</param>
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//獲得參數數組
var arguments = e.Argument as object[];
//獲得回調方法
var completeMethod = arguments[0];
//獲得業務實體
var businessObject = arguments[1];
//獲得方法名
var methodName = arguments[2] as string;
//獲得參數
var args = arguments[3] as object[];
//通知回調
Reports = arguments[5] as Action<TReport, Exception>;
//存放結果
object result = null;
//存放異常
Exception ex = null;
try
{
//參數類型集合
List<Type> lstArgType = new List<Type>();
//把所有參數的類型填入集合
if (args != null && args.Length > 0)
{
for (int i = 0; i < args.Length; i++)
{
lstArgType.Add(args[i].GetType());
}
}
//獲得方法
var method = GetTarMethod(businessObject.GetType(), methodName, lstArgType.ToArray());
//如果沒找到該方法,直接執行該業務實體的方法
if (method == null)
{
//執行,並把結果賦給結果對象
result = businessObject.GetType().GetMethod(methodName, lstArgType.ToArray()).Invoke(businessObject, args);
}
//如果找到了方法,則通過接口調方法
else
{
result = method.Invoke(businessObject, args);
}
}
catch (Exception exThread)
{
ex = exThread;
}
//結果由參數帶回
e.Result = new object[] { result, completeMethod, ex, arguments[6] };
}
/// <summary>
/// 回調方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var results = e.Result as object[];
//取出結果
var result = results[0];
Exception ex = null;
//如果結果帶出的異常不爲空
if (results[2] != null)
{
var exThread = results[2] as Exception;
//如果內部異常不爲空,則取內部異常
if (exThread.InnerException != null)
{
ex = exThread.InnerException;
}
//否則直接取總異常
else
{
ex = exThread;
}
}
try
{
//取出回調委託
Action<TResult, Exception> method = results[1] as Action<TResult, Exception>;
//如果返回結果爲空,傳該類型的默認值
if (result == null)
{
method(default(TResult), ex);
}
//否則傳帶出的結果
else
{
method((TResult)result, ex);
}
}
//應對回調時回調對象已被銷燬
catch (Exception exc)
{
//把除了訪問已釋放的資源異常吃掉外,其他異常拋出,方便調試
if (!(exc is ObjectDisposedException))
{
throw exc;
}
}
finally
{
//及時清除引用,防止以後錯誤調用的干擾
SelfBackgroundWorker = null;
if(!((bool)results[3]))
{
InnerBackGroundWorker.RunWorkerAsync();
}
}
}
/// <summary>
/// 進度改變事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//如果通知回調不爲空
if (Reports != null)
{
//提出方法參數
var arguments = e.UserState as object[];
Reports((TReport)arguments[0], arguments[1] as Exception);
}
}
/// <summary>
/// 獲得目標方法
/// </summary>
/// <param name="svcType">方法所在類型</param>
/// <param name="methodName">方法名</param>
/// <param name="argTypes">參數類型集合</param>
/// <returns>方法信息</returns>
private static MethodInfo GetTarMethod(Type svcType, string methodName, Type[] argTypes)
{
//獲取由當前實體所實現的接口集合
foreach (var item in svcType.GetInterfaces())
{
//通過名稱和類型找方法
var method = item.GetMethod(methodName, argTypes);
//找到方法就返回
if (method != null)
{
return method;
}
}
return null;
}
#endregion
}
#endregion
#region 不帶返回類型的異步工具-含報告
///<summary NoteObject="Class">
/// [功能描述:管理的的帶報告的異步工具類,對於調用異步時使用單獨線程的操作就千萬不要調用Report方法,因爲單獨線程已經不處於託管環境了,此時調Report會干擾託管的線程] <para/>
/// [創建者:張聯珠] <para/>
/// [創建時間:2014年4月11日] <para/>
///<說明>
/// [說明:修改原工具類
/// 使用說明:後臺操作方法不要訪問UI資源]<para/>
///</說明>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///<修改記錄>
/// [修改時間:本次修改時間]<para/>
/// [修改內容:本次修改內容]<para/>
///</修改記錄>
///</summary>
public static class ManagedAsyncUtilsWithReport<TReport>
{
#region 字段
/// <summary>
/// 私有的靜態工作對象
/// </summary>
private static BackgroundWorker SelfBackgroundWorker = null;
/// <summary>
/// 通知回調
/// </summary>
private static Action<TReport, Exception> Reports;
#endregion
#region 構造函數
/// <summary>
/// 使用前初始化異步工具
/// </summary>
public static void InitUtil(BackgroundWorker backGroundWorker)
{
SelfBackgroundWorker = backGroundWorker;
SelfBackgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
SelfBackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
SelfBackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
//支持報告進度
SelfBackgroundWorker.WorkerReportsProgress = true;
}
#endregion
#region 對外提供的方法
/// <summary>
/// 異步調用
/// </summary>
/// <param name="invokeCompleted">回調方法委託()回調的方法可以不是公有的,因爲使用委託了</param>
/// <param name="reportChanged">通知改變的回調方法委託(該參數可以爲空,爲空就不通知改變,如果傳入該參數不爲空,可以調用Report方法來反信息)回調的方法可以不是公有的,因爲使用委託了</param>
/// <param name="businessObject">調用目標對象實例(後臺方法所在類的對象)</param>
/// <param name="methodName">後臺執行的方法名稱(要申明成公有,應爲內部通過反射來訪問,不是公有的話會訪問不到。該操作方法不要訪問UI資源,在回調方法裏訪問)</param>
/// <param name="args">後臺執行方法需要的參數(和參數順序一樣的object數組)</param>
/// <param name="isSelfAsy">是否單獨一個異步</param>
public static void Invoke(Action<Exception> invokeCompleted, Action<TReport, Exception> reportChanged, object businessObject,
string methodName, object[] args, bool isSelfAsy=false)
{
if (!isSelfAsy)
{
lock (InnerBackGroundWorker.Lock)
{
InnerBackGroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil),reportChanged, isSelfAsy });
}
}
else
{
InitUtil(new BackgroundWorker());
SelfBackgroundWorker.RunWorkerAsync(new object[] { invokeCompleted, businessObject, methodName, args, new InitAsyUtil(InitUtil),reportChanged ,isSelfAsy });
}
}
/// <summary>
/// 報告事件
/// </summary>
/// <param name="reportInfo">報告內容</param>
/// <param name="ex">報告異常</param>
public static void Report(TReport reportInfo, Exception ex)
{
object[] args = new object[] { reportInfo, ex };
SelfBackgroundWorker.ReportProgress(0, args);
}
#endregion
#region 內部方法
/// <summary>
/// 後臺工作方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//提出方法參數
var arguments = e.Argument as object[];
//提出回調委託
var completeMethod = arguments[0];
//提出調用方法的對象
var businessObject = arguments[1];
//提出調用方法的名稱
var methodName = arguments[2] as string;
//提出調用方法的參數
var args = arguments[3] as object[];
//通知回調
Reports = arguments[5] as Action<TReport, Exception>;
//異常
Exception ex = null;
try
{
//存所有的參數類型
List<Type> lstArgType = new List<Type>();
if (args != null && args.Length > 0)
{
for (int i = 0; i < args.Length; i++)
{
lstArgType.Add(args[i].GetType());
}
}
//獲得調用方法
var method = GetTarMethod(businessObject.GetType(), methodName, lstArgType.ToArray());
if (method == null)
{
businessObject.GetType().GetMethod(methodName, lstArgType.ToArray()).Invoke(businessObject, args);
}
else
{
method.Invoke(businessObject, args);
}
}
catch (Exception exThread)
{
ex = exThread;
}
//結果由參數帶回
e.Result = new object[] { completeMethod, ex, arguments[6] };
}
/// <summary>
/// 獲得目標方法
/// </summary>
/// <param name="svcType">方法所在類型</param>
/// <param name="methodName">方法名</param>
/// <param name="argTypes">參數類型集合</param>
/// <returns>方法信息</returns>
private static MethodInfo GetTarMethod(Type svcType, string methodName, Type[] argTypes)
{
foreach (var item in svcType.GetInterfaces())
{
var method = item.GetMethod(methodName, argTypes);
if (method != null)
{
return method;
}
}
return null;
}
/// <summary>
/// 進度改變事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//如果通知回調不爲空
if (Reports != null)
{
//提出方法參數
var arguments = e.UserState as object[];
Reports((TReport)arguments[0], arguments[1] as Exception);
}
}
/// <summary>
/// 回調方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//取出結果
var results = e.Result as object[];
try
{
//取出回調方法
var method = results[0] as Action<Exception>;
if (results[1] != null)
{
var exThread = results[1] as Exception;
if (exThread.InnerException != null)
{
method(exThread.InnerException);
}
else
{
method(exThread);
}
}
else
{
method(null);
}
}
//應對回調時回調對象已被銷燬
catch(Exception exc)
{
//把除了訪問已釋放的資源異常吃掉外,其他異常拋出,方便調試
if (!(exc is ObjectDisposedException))
{
throw exc;
}
}
finally
{
//及時清除引用,防止以後錯誤調用的干擾
SelfBackgroundWorker = null;
if (!((bool)results[2]))
{
InnerBackGroundWorker.RunWorkerAsync();
}
}
}
#endregion
}
#endregion
}
開啓後臺調用事列
LIS.Core.Util.LogUtils.WriteDebugLog("準備異步監聽");
//創建異步工具類的回調委託
Action<Exception> workerCompleted = new Action<Exception>(DealReturn);
//創建異步工具類的回調委託
Action<LogDto, Exception> workerCahnge = new Action<LogDto, Exception>(DealChange);
//組裝參數
object[] paras = new object[] { };
//初始化工具
ManagedAsyncUtilsWithReport<LogDto>.InitUtil(new BackgroundWorker());
LIS.Core.Util.LogUtils.WriteDebugLog("監聽程序開啓監聽");
ManagedAsyncUtilsWithReport<LogDto>.Invoke(workerCompleted, workerCahnge, this, "StartMonitor", paras);
回調方法
/// <summary>
/// 處理返回的回調
/// </summary>
/// <param name="ex"></param>
public void DealReturn(Exception ex)
{
if (ex != null)
{
LIS.Core.Util.LogUtils.WriteDebugLog("監聽過程發生錯誤" + ex.Message);
//對網絡錯誤彈窗提示,並退出程序
if (ex.Message.Contains("沒有終結點在偵聽可以接受消息的"))
{
MessageBox.Show("網絡錯誤,請確認電腦的連網狀態!無法傳輸LIS數據,網絡恢復後請重新打開監聽程序", "iMedicalLIS監聽提示");
}
//對網絡錯誤彈窗提示,並退出程序
if (ex.Message.Contains("無法連接到遠程服務器"))
{
MessageBox.Show("網絡錯誤,請確認電腦的連網狀態!無法傳輸LIS數據,網絡恢復後請重新打開監聽程序", "iMedicalLIS監聽提示");
}
}
if (PreDeal.Interface.BaseDeal.DealDataNum > waringNum)
{
MessageBox.Show("監聽程序當天調用保存數據次數超過" + waringNum + "次,請聯繫工程師查看是否有異常情況!", "溫馨提示");
}
//創建異步工具類的回調委託
Action<Exception> workerCompleted = new Action<Exception>(DealReturn);
//創建異步工具類的回調委託
Action<LogDto, Exception> workerCahnge = new Action<LogDto, Exception>(DealChange);
//組裝參數
object[] paras = new object[] { };
//初始化工具
ManagedAsyncUtilsWithReport<LogDto>.InitUtil(new BackgroundWorker());
ManagedAsyncUtilsWithReport<LogDto>.Invoke(workerCompleted, workerCahnge, this, "StartMonitor", paras);
}
/// <summary>
/// 處理數據改變
/// </summary>
/// <param name="ex">異常信息</param>
public void DealChange(LogDto dto, Exception ex)
{
//窗口是打開狀態才綁數據
if (this.WindowState != FormWindowState.Minimized)
{
//組裝參數
object[] paras = new object[] { dto.Result };
this.Invoke(new BindDataDelegate(BindData), paras);
}
}
線程方法和通知UI
/// <summary>
/// 開始監聽
/// </summary>
public void StartMonitor()
{
LogDto dt = new LogDto();
dt.Address = "";
dt.Time = DateTime.Now.ToString();
//窗口是打開狀態才綁數據
if (this.WindowState != FormWindowState.Minimized)
{
ManagedAsyncUtilsWithReport<LogDto>.InitUtil(new BackgroundWorker());
//通知界面改變
ManagedAsyncUtilsWithReport<LogDto>.Report(dt, null);
}
LIS.Core.Util.LogUtils.WriteDebugLog("一輪監聽結束,休眠" + sleepTime + "毫秒");
//阻塞進程
System.Threading.Thread.Sleep(sleepTime);
//有數據改變爲活動圖標
ChangeIcon(2);
}