这个类库是在codeproject上发现的,主要是用于在.net 2.0,3.5的框架下,不可以在非创建线程下雨控件进行交互的限制,类库封装得比较好,使用了匿名方法。
Code
// Copyright (c) 2008 CodeToast.com and Nicholas Brookins
//This code is free to use in any application for any use if this notice is left intact.
//Just don't sue me if it gets you fired. Enjoy!![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Windows.Forms;![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
namespace CodeToast
{ ![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static class Async
{ ![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
static Dictionary<string, object> methodLocks = new Dictionary<string, object>();![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Async 'Do' overloads, for ease of use#region Async 'Do' overloads, for ease of use![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// This overload always tries the ThreadPool and DOES NOT check for reentrance.
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static AsyncRes Do(DlgR d, bool getRetVal)
{
return Do(d, getRetVal, ReenteranceMode.Allow);
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// This overload always tries the ThreadPool and DOES NOT check for reentrance.
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method: Async.Do((Dlg)MyVoidMethod)</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static AsyncRes Do(Dlg d)
{
return Do(d, ReenteranceMode.Allow);
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, resturn and result values, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static AsyncRes Do(DlgR d, bool getRetVal, ReenteranceMode rMode)
{
return Do(d, null, getRetVal, null, true, rMode, null, true);
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method: Async.Do((Dlg)MyVoidMethod);</param>![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static AsyncRes Do(Dlg d, ReenteranceMode rMode)
{
return Do(null, d, false, null, true, rMode, null, true);
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="state">A user object that can be tracked through the returned result</param>
/// <param name="tryThreadPool">True to use the TP, otherwise just go to a ful lthread - good for long running tasks.</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, resturn and result values, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static AsyncRes Do(DlgR d, bool getRetVal, object state, bool tryThreadPool, ReenteranceMode rMode)
{
return Do(d, null, getRetVal, state, tryThreadPool, rMode, null, true);
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method: Async.Do((Dlg)MyVoidMethod);</param>
/// <param name="state">A user object that can be tracked through the returned result</param>
/// <param name="tryThreadPool">True to use the TP, otherwise just go to a ful lthread - good for long running tasks.</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static AsyncRes Do(Dlg d, object state, bool tryThreadPool, ReenteranceMode rMode)
{
return Do(null, d, false, state, tryThreadPool, rMode, null, true);
}
#endregion![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
The Big Main private 'Do' method - called by all overloads.#region The Big Main private 'Do' method - called by all overloads.![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate.</param>
/// <param name="dr">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return.</param>
/// <param name="state">A user object that can be tracked through the returned result</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <param name="tryThreadPool">True to use the TP, otherwise just go to a ful lthread - good for long running tasks.</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
private static AsyncRes Do(DlgR dr, Dlg d, bool getRetVal, object state, bool tryThreadPool, ReenteranceMode rMode, Control control, bool async)
{
//get a generic MethodInfo for checks..
MethodInfo mi = ((dr != null) ? dr.Method : d.Method);
//make a unique key for output usage
string key = string.Format("{0}{1}{2}{3}", ((getRetVal) ? "<-" : ""), mi.DeclaringType, ((mi.IsStatic) ? ":" : "."), mi.Name);
//our custom return value, holds our delegate, state, key, etc.
AsyncRes res = new AsyncRes(state, ((dr != null) ? (Delegate)dr : (Delegate)d), key, rMode);![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//Create a delegate wrapper for what we will actually invoke..![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
Dlg dlg = (Dlg)delegate
{
if (!BeforeInvoke(res)) return; //checks for reentrance issues and sets us up![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
try
{
if (res.IsCompleted) return;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (dr != null)
{
res.retVal = dr();//use this one if theres a return![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} else
{
d();//otherwise the simpler dlg
}![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} catch (Exception ex)
{ //we never want a rogue exception on a random thread, it can't bubble up anywhere
Console.WriteLine("Async Exception:" + ex);![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} finally
{
FinishInvoke(res);//this will fire our callback if they used it, and clean up
}
};![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (control != null)
{
res.control = control;
res.result = AsyncAction.ControlInvoked;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!async)
{ ![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!control.InvokeRequired)
{
res.completedSynchronously = true;
dlg();![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} else
{
control.Invoke(dlg);
}![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} else
{
control.BeginInvoke(dlg);
}
return res;
} //don't catch these errors - if this fails, we shouldn't try a real thread or threadpool!![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (tryThreadPool)
{ //we are going to use the .NET threadpool![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
try
{
//get some stats - much better than trying and silently failing or throwing an expensive exception
int minThreads, minIO, threads, ioThreads, totalThreads, totalIO;
ThreadPool.GetMinThreads(out minThreads, out minIO);
ThreadPool.GetAvailableThreads(out threads, out ioThreads);
ThreadPool.GetMaxThreads(out totalThreads, out totalIO);![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//check for at least our thread plus one more in ThreadPool![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (threads > minThreads)
{
//this is what actually fires this task off..![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
bool result = ThreadPool.QueueUserWorkItem((WaitCallback)delegate
{ dlg(); });![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (result)
{
res.result = AsyncAction.ThreadPool;
//this means success in queueing and running the item
return res;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} else
{
//according to docs, this "won't ever happen" - exception instead, but just for kicks.
Console.WriteLine( "Failed to queue in threadpool.", "Method: " + key);
}![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} else
{
Console.WriteLine(String.Format("Insufficient idle threadpool threads: {0} of {1} - min {2}, Method: {3}", threads, totalThreads, minThreads, key));
}![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} catch (Exception ex)
{
Console.WriteLine("Failed to queue in threadpool: " + ex.Message, "Method: " + key);
}
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//if we got this far, then something up there failed, or they wanted a dedicated thread![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
Thread t = new Thread((ThreadStart)delegate
{ dlg(); });
t.IsBackground = true; //this or threadpriority are candidates for additional settings
t.Name = "Async_" + key;
res.result = AsyncAction.Thread;
t.Start();![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return res;
}
#endregion![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Before and after - helper methods#region Before and after - helper methods![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
private static bool BeforeInvoke(AsyncRes res)
{
//if marked as completed then we abort.
if (res.IsCompleted) return false;
//if mode is 'allow' there is nothing to check. Otherwise![](https://www.cnblogs.com/Images/dot.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (res.RMode != ReenteranceMode.Allow)
{
//be threadsafe with our one and only member field![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
lock (methodLocks)
{ ![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!methodLocks.ContainsKey(res.Method))
{
//make sure we have a generic locking object in the collection, it will already be there if we are reentering
methodLocks.Add(res.Method, new object());
}
//if bypass mode and we can't get or lock, we dump out.![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (res.RMode == ReenteranceMode.Bypass)
{ ![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (!Monitor.TryEnter(methodLocks[res.Method]))
{
res.result = AsyncAction.Reenterant;
return false;
}![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} else
{
//Otherwise in 'stack' mode, we just wait until someone else releases it![](https://www.cnblogs.com/Images/dot.gif)
Monitor.Enter(methodLocks[res.Method]);
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//if we are here, all is good.
//Set some properties on the result class to show when we started, and what thread we are on
res.isStarted = true;
res.startTime = DateTime.Now;
res.thread = Thread.CurrentThread;
}
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return true;
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
private static void FinishInvoke(AsyncRes res)
{
if (res == null) return;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
try
{
//finish a few more properties
res.isCompleted = true;
res.completeTime = DateTime.Now;
//set the resetevent, in case someone is using the waithandle to know when we have completed.
res.mre.Set();![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} catch (Exception ex)
{
Console.WriteLine("Error setting wait handle on " + (res.Method ?? "NULL") + ex);
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (res.RMode != ReenteranceMode.Allow)
{
//if mode is bypass or stack, then we must have a lock that needs releasing![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
try
{ ![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (methodLocks.ContainsKey(res.Method))
{
Monitor.Exit(methodLocks[res.Method]);
}![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
} catch (Exception ex)
{
Console.WriteLine("Error releasing reentrant lock on " + (res.Method ?? "NULL")+ ex);
}
}
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
UI Overloads#region UI Overloads![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate, carefully using the correct UI thread
/// </summary>
/// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method: Async.Do((Dlg)MyVoidMethod);</param>
/// <param name="async">Whether to run async, or try on current thread if invoke is not required.</param>
/// <param name="c">A control to Invoke upon GUI thread of, if needed. Null if unused.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static AsyncRes UI(Dlg d, Control c, bool async)
{
return Do(null, d, false, null, false, ReenteranceMode.Allow, c, async);
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate, carefully using the correct UI thread
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="async">Whether to run async, or try on current thread if invoke is not required.</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <param name="c">A control to Invoke upon GUI thread of, if needed. Null if unused.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static AsyncRes UI(DlgR d, bool getRetVal, Control c, bool async)
{
return Do(d, null, getRetVal, null, false, ReenteranceMode.Allow, c, async);
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Fires off your delegate, carefully using the correct UI thread
/// </summary>
/// <param name="d">A delegate with a return value of some sort - can be cast to (DlgR) from an anonymous delgate with a return: Async.Do((DlgR)MyMethod);</param>
/// <param name="state">A user object that can be tracked through the returned result</param>
/// <param name="async">Whether to run async, or try on current thread if invoke is not required.</param>
/// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
/// <param name="rMode">If true, will make sure no other instances are running your method.</param>
/// <param name="c">A control to Invoke upon GUI thread of, if needed. Null if unused.</param>
/// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static AsyncRes UI(DlgR d, bool getRetVal, Control c, object state, bool async, ReenteranceMode rMode)
{
return Do(d, null, getRetVal, state, false, rMode, c, async);
}
#endregion
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
AsyncRes class#region AsyncRes class![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Used with the Async helper class, This class is mostly a holder for a lot of tracking fields and properties, with a few things mandated by the IAsyncResult interface.
/// </summary>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public class AsyncRes : IAsyncResult
{ ![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
internal AsyncRes(object state, Delegate d, string key, ReenteranceMode rMode)
{
this.state = state;
this.asyncDelegate = d;
this.key = key;
this.RMode = rMode;
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal ReenteranceMode RMode = ReenteranceMode.Allow;![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal Thread thread = null;![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private string key = null;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public string Method
{ get
{ return key; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private Delegate asyncDelegate = null;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public Delegate AsyncDelegate
{ get
{ return asyncDelegate; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal AsyncAction result = AsyncAction.Unknown;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public AsyncAction Result
{ get
{ return result; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal Control control = null;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public Control Control
{ get
{ return control; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal DateTime createTime = DateTime.Now;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public DateTime TimeCreated
{ get
{ return createTime; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal DateTime completeTime = DateTime.MinValue;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public DateTime TimeCompleted
{ get
{ return completeTime; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal DateTime startTime = DateTime.Now;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public DateTime TimeStarted
{ get
{ return startTime; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public TimeSpan TimeElapsed
{ ![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return ((completeTime > DateTime.MinValue) ? completeTime : DateTime.Now) - createTime; }
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public TimeSpan TimeRunning
{ ![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return (startTime == DateTime.MinValue) ? TimeSpan.Zero : ((completeTime > DateTime.MinValue) ? completeTime : DateTime.Now) - startTime;}
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal object retVal = null;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public object ReturnValue
{ get
{ return retVal; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal bool isStarted = false;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public bool IsStarted
{ get
{ return isStarted; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private object state = null;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public object AsyncState
{ get
{ return state; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Aborts a running associated thread. If possible it will cancel if not yet started
/// </summary>
/// <returns>True if the thread could be cancelled before it started.</returns>![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public bool CancelOrAbort()
{
isCompleted = true;
if (!isStarted) return true;//cancelled![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (thread != null && thread.IsAlive)
{
thread.Abort();
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return false;
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal ManualResetEvent mre = new ManualResetEvent(false);![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public WaitHandle AsyncWaitHandle
{ get
{ return mre; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal bool completedSynchronously = false;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public bool CompletedSynchronously
{ get
{ return completedSynchronously; } }![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
internal bool isCompleted = false;![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public bool IsCompleted
{ get
{ return isCompleted; } }
}
#endregion![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Definitions of enums and delegates#region Definitions of enums and delegates![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Abreviated Empty Delegate for use in anonymous casting
/// </summary>
public delegate void Dlg();![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
/// Abreviated Empty Delegate for use in anonymous methods when a return is needed
/// </summary>
/// <returns>Umm, anything you want.</returns>
public delegate object DlgR();![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public enum AsyncAction
{
Unknown = 0,
ThreadPool = 1,
Thread = 2,
Failed = 4,
Reenterant = 8,
ControlInvoked = 16
}![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public enum ReenteranceMode
{
Allow = 1,
Bypass = 2,
Stack = 4,
}
#endregion
}
异步获取控件值:
Code
AsyncRes result = Async.UI(
//make sure the delegate/method returns a value:![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
delegate
{ return textBox1.Text; },
true, //yes, we want to get the return value
myForm, //the control to invoke on
null, //the state object, we don't need to track anything.
true, //invoke asynchronously?
ReenteranceMode.Allow); //don't worry about thread safety in this case.![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
//
. do other things
//![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// now make sure the task above has completed..
result.AsyncWaitHandle.WaitOne();![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
//and use the value
Console.WriteLine("The textbox says: " + result.ReturnValue);![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
同步设置控件值:
Code Async.UI(delegate { textBox1.Text = "This is way easier!"; }, textBox1, true);