推荐一个winform 界面交互类库

来源:互联网 发布:绝密淘宝小类目 编辑:程序博客网 时间:2024/05/26 12:54
这个类库是在codeproject上发现的,主要是用于在.net 2.0,3.5的框架下,不可以在非创建线程下雨控件进行交互的限制,类库封装得比较好,使用了匿名方法。
  1. // Copyright (c) 2008 CodeToast.com and Nicholas Brookins
  2. //This code is free to use in any application for any use if this notice is left intact.
  3. //Just don't sue me if it gets you fired.  Enjoy!

  4. using System;
  5. using System.Collections.Generic;
  6. using System.Reflection;
  7. using System.Text;
  8. using System.Runtime.Remoting.Messaging;
  9. using System.Threading;
  10. using System.Windows.Forms;

  11. namespace CodeToast {
  12.     public static class Async {

  13.         static Dictionary<string, object> methodLocks = new Dictionary<string, object>();

  14.         Async 'Do' overloads, for ease of use#region Async 'Do' overloads, for ease of use
  15.         /**//// <summary>
  16.         /// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed. 
  17.         /// This overload always tries the ThreadPool and DOES NOT check for reentrance.
  18.         /// </summary>
  19.         /// <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>
  20.         /// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
  21.         /// <returns>AsyncRes with all kind o' goodies for waiting, etc.</returns>
  22.         public static AsyncRes Do(DlgR d, bool getRetVal) {
  23.             return Do(d, getRetVal, ReenteranceMode.Allow);
  24.         }

  25.         /**//// <summary>
  26.         /// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed. 
  27.         /// This overload always tries the ThreadPool and DOES NOT check for reentrance.
  28.         /// </summary>
  29.         /// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method:  Async.Do((Dlg)MyVoidMethod)</param>
  30.         /// <returns>AsyncRes with all kind o' goodies for waiting, etc.</returns>
  31.         public static AsyncRes Do(Dlg d) {
  32.             return Do(d, ReenteranceMode.Allow);
  33.         }

  34.         /**//// <summary>
  35.         /// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
  36.         /// </summary>
  37.         /// <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>
  38.         /// <param name="rMode">If true, will make sure no other instances are running your method.</param>
  39.         /// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
  40.         /// <returns>AsyncRes with all kind o' goodies for waiting, resturn and result values, etc.</returns>
  41.         public static AsyncRes Do(DlgR d, bool getRetVal, ReenteranceMode rMode) {
  42.             return Do(d, null, getRetVal, null, true, rMode, null, true);
  43.         }

  44.         /**//// <summary>
  45.         /// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
  46.         /// </summary>
  47.         /// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method:  Async.Do((Dlg)MyVoidMethod);</param>

  48.         /// <param name="rMode">If true, will make sure no other instances are running your method.</param>
  49.         /// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>
  50.         public static AsyncRes Do(Dlg d, ReenteranceMode rMode) {
  51.             return Do(null, d, false, null, true, rMode, null, true);
  52.         }

  53.         /**//// <summary>
  54.         /// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
  55.         /// </summary>
  56.         /// <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>
  57.         /// <param name="state">A user object that can be tracked through the returned result</param>
  58.         /// <param name="tryThreadPool">True to use the TP, otherwise just go to a ful lthread - good for long running tasks.</param>
  59.         /// <param name="rMode">If true, will make sure no other instances are running your method.</param>
  60.         /// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
  61.         /// <returns>AsyncRes with all kind o' goodies for waiting, resturn and result values, etc.</returns>
  62.         public static AsyncRes Do(DlgR d, bool getRetVal, object state, bool tryThreadPool, ReenteranceMode rMode) {
  63.             return Do(d, null, getRetVal, state, tryThreadPool, rMode, null, true);
  64.         }

  65.         /**//// <summary>
  66.         /// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
  67.         /// </summary>
  68.         /// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method:  Async.Do((Dlg)MyVoidMethod);</param>
  69.         /// <param name="state">A user object that can be tracked through the returned result</param>
  70.         /// <param name="tryThreadPool">True to use the TP, otherwise just go to a ful lthread - good for long running tasks.</param>
  71.         /// <param name="rMode">If true, will make sure no other instances are running your method.</param>
  72.         /// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>
  73.         public static AsyncRes Do(Dlg d, object state, bool tryThreadPool, ReenteranceMode rMode) {
  74.             return Do(null, d, false, state, tryThreadPool, rMode, null, true);
  75.         }
  76.         #endregion

  77.         The Big Main private 'Do' method - called by all overloads.#region The Big Main private 'Do' method - called by all overloads.
  78.         /**//// <summary>
  79.         /// Fires off your delegate asyncronously, using the threadpool or a full managed thread if needed.
  80.         /// </summary>
  81.         /// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate.</param>
  82.         /// <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>
  83.         /// <param name="state">A user object that can be tracked through the returned result</param>
  84.         /// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
  85.         /// <param name="tryThreadPool">True to use the TP, otherwise just go to a ful lthread - good for long running tasks.</param>
  86.         /// <param name="rMode">If true, will make sure no other instances are running your method.</param>
  87.         /// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>
  88.         private static AsyncRes Do(DlgR dr, Dlg d, bool getRetVal, object state, bool tryThreadPool, ReenteranceMode rMode, Control control, bool async) {
  89.             //get a generic MethodInfo for checks..
  90.             MethodInfo mi = ((dr != null) ? dr.Method : d.Method);
  91.             //make a unique key for output usage
  92.             string key = string.Format("{0}{1}{2}{3}", ((getRetVal) ? "<-" : ""), mi.DeclaringType, ((mi.IsStatic) ? ":" : "."), mi.Name);
  93.             //our custom return value, holds our delegate, state, key, etc.
  94.             AsyncRes res = new AsyncRes(state, ((dr != null) ? (Delegate)dr : (Delegate)d), key, rMode);

  95.             //Create a delegate wrapper for what we will actually invoke..
  96.             Dlg dlg = (Dlg)delegate {
  97.                 if (!BeforeInvoke(res)) return; //checks for reentrance issues and sets us up
  98.                 try {
  99.                     if (res.IsCompleted) return;
  100.                     if (dr != null) {
  101.                         res.retVal = dr();//use this one if theres a return
  102.                     } else {
  103.                         d();//otherwise the simpler dlg
  104.                     }
  105.                 } catch (Exception ex) { //we never want a rogue exception on a random thread, it can't bubble up anywhere
  106.                     Console.WriteLine("Async Exception:" + ex);
  107.                 } finally {
  108.                     FinishInvoke(res);//this will fire our callback if they used it, and clean up
  109.                 }
  110.             };

  111.             if (control != null) {
  112.                 res.control = control;
  113.                 res.result = AsyncAction.ControlInvoked;
  114.                 if (!async) {
  115.                     if (!control.InvokeRequired) {
  116.                         res.completedSynchronously = true;
  117.                         dlg();
  118.                     } else {
  119.                         control.Invoke(dlg);
  120.                     }
  121.                 } else {
  122.                     control.BeginInvoke(dlg);
  123.                 }
  124.                 return res;
  125.             } //don't catch these errors - if this fails, we shouldn't try a real thread or threadpool!

  126.             if (tryThreadPool) { //we are going to use the .NET threadpool
  127.                 try {
  128.                     //get some stats - much better than trying and silently failing or throwing an expensive exception
  129.                     int minThreads, minIO, threads, ioThreads, totalThreads, totalIO;
  130.                     ThreadPool.GetMinThreads(out minThreads, out minIO);
  131.                     ThreadPool.GetAvailableThreads(out threads, out ioThreads);
  132.                     ThreadPool.GetMaxThreads(out totalThreads, out totalIO);

  133.                     //check for at least our thread plus one more in ThreadPool
  134.                     if (threads > minThreads) {
  135.                         //this is what actually fires this task off..
  136.                         bool result = ThreadPool.QueueUserWorkItem((WaitCallback)delegate { dlg(); });
  137.                         if (result) {
  138.                             res.result = AsyncAction.ThreadPool;
  139.                             //this means success in queueing and running the item
  140.                             return res;
  141.                         } else {
  142.                             //according to docs, this "won't ever happen" - exception instead, but just for kicks.
  143.                             Console.WriteLine( "Failed to queue in threadpool.", "Method: " + key);
  144.                         }
  145.                     } else {
  146.                         Console.WriteLine(String.Format("Insufficient idle threadpool threads: {0} of {1} - min {2}, Method: {3}", threads, totalThreads, minThreads, key));
  147.                     }
  148.                 } catch (Exception ex) {
  149.                     Console.WriteLine("Failed to queue in threadpool: " + ex.Message, "Method: " + key);
  150.                 }
  151.             }

  152.             //if we got this far, then something up there failed, or they wanted a dedicated thread
  153.             Thread t = new Thread((ThreadStart)delegate { dlg(); });
  154.             t.IsBackground = true; //this or threadpriority are candidates for additional settings
  155.             t.Name = "Async_" + key;
  156.             res.result = AsyncAction.Thread;
  157.             t.Start();

  158.             return res;
  159.         }
  160.         #endregion

  161.         Before and after - helper methods#region Before and after - helper methods

  162.         private static bool BeforeInvoke(AsyncRes res) {
  163.             //if marked as completed then we abort.
  164.             if (res.IsCompleted) return false;
  165.             //if mode is 'allow' there is nothing to check.  Otherwise
  166.             if (res.RMode != ReenteranceMode.Allow) {
  167.                 //be threadsafe with our one and only member field
  168.                 lock (methodLocks) {
  169.                     if (!methodLocks.ContainsKey(res.Method)) {
  170.                         //make sure we have a generic locking object in the collection, it will already be there if we are reentering
  171.                         methodLocks.Add(res.Method, new object());
  172.                     }
  173.                     //if bypass mode and we can't get or lock, we dump out.
  174.                     if (res.RMode == ReenteranceMode.Bypass) {
  175.                         if (!Monitor.TryEnter(methodLocks[res.Method])) {
  176.                             res.result = AsyncAction.Reenterant;
  177.                             return false;
  178.                         }
  179.                     } else {
  180.                         //Otherwise in 'stack' mode, we just wait until someone else releases it
  181.                         Monitor.Enter(methodLocks[res.Method]);
  182.                     }

  183.                     //if we are here, all is good.  
  184.                     //Set some properties on the result class to show when we started, and what thread we are on
  185.                     res.isStarted = true;
  186.                     res.startTime = DateTime.Now;
  187.                     res.thread = Thread.CurrentThread;
  188.                 }
  189.             }

  190.             return true;
  191.         }

  192.         private static void FinishInvoke(AsyncRes res) {
  193.             if (res == null) return;
  194.             try {
  195.                 //finish a few more properties
  196.                 res.isCompleted = true;
  197.                 res.completeTime = DateTime.Now;
  198.                 //set the resetevent, in case someone is using the waithandle to know when we have completed.
  199.                 res.mre.Set();
  200.             } catch (Exception ex) {
  201.                 Console.WriteLine("Error setting wait handle on " + (res.Method ?? "NULL") + ex);
  202.             }

  203.             if (res.RMode != ReenteranceMode.Allow) {
  204.                 //if mode is bypass or stack, then we must have a lock that needs releasing
  205.                 try {
  206.                     if (methodLocks.ContainsKey(res.Method)) {
  207.                         Monitor.Exit(methodLocks[res.Method]);
  208.                     }
  209.                 } catch (Exception ex) {
  210.                     Console.WriteLine("Error releasing reentrant lock on " + (res.Method ?? "NULL")+ ex);
  211.                 }
  212.             }
  213.         }

  214.         #endregion

  215.         UI Overloads#region UI Overloads
  216.         /**//// <summary>
  217.         /// Fires off your delegate, carefully using the correct UI thread
  218.         /// </summary>
  219.         /// <param name="d">A void delegate - can be cast to (Dlg) from an anonymous delgate or method:  Async.Do((Dlg)MyVoidMethod);</param>
  220.         /// <param name="async">Whether to run async, or try on current thread if invoke is not required.</param>
  221.         /// <param name="c">A control to Invoke upon GUI thread of, if needed. Null if unused.</param>
  222.         /// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>
  223.         public static AsyncRes UI(Dlg d, Control c, bool async) {
  224.             return Do(null, d, false, null, false, ReenteranceMode.Allow, c, async);
  225.         }

  226.         /**//// <summary>
  227.         /// Fires off your delegate, carefully using the correct UI thread
  228.         /// </summary>
  229.         /// <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>
  230.         /// <param name="async">Whether to run async, or try on current thread if invoke is not required.</param>
  231.         /// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
  232.         /// <param name="c">A control to Invoke upon GUI thread of, if needed. Null if unused.</param>
  233.         /// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>
  234.         public static AsyncRes UI(DlgR d, bool getRetVal, Control c, bool async) {
  235.             return Do(d, null, getRetVal, null, false, ReenteranceMode.Allow, c, async);
  236.         }

  237.         /**//// <summary>
  238.         /// Fires off your delegate, carefully using the correct UI thread
  239.         /// </summary>
  240.         /// <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>
  241.         /// <param name="state">A user object that can be tracked through the returned result</param>
  242.         /// <param name="async">Whether to run async, or try on current thread if invoke is not required.</param>
  243.         /// <param name="getRetVal">If true, and the method/delgete returns something, it is included in the AsyncRes returned (after the method completes)</param>
  244.         /// <param name="rMode">If true, will make sure no other instances are running your method.</param>
  245.         /// <param name="c">A control to Invoke upon GUI thread of, if needed. Null if unused.</param>
  246.         /// <returns>AsyncRes with all kind o' goodies for waiting, result values, etc.</returns>
  247.         public static AsyncRes UI(DlgR d, bool getRetVal, Control c, object state, bool async, ReenteranceMode rMode) {
  248.             return Do(d, null, getRetVal, state, false, rMode, c, async);
  249.         }
  250.         #endregion
  251.     }

  252.     AsyncRes class#region AsyncRes class
  253.     /**//// <summary>
  254.     /// 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.
  255.     /// </summary>
  256.     public class AsyncRes : IAsyncResult {

  257.         internal AsyncRes(object state, Delegate d, string key, ReenteranceMode rMode) {
  258.             this.state = state;
  259.             this.asyncDelegate = d;
  260.             this.key = key;
  261.             this.RMode = rMode;
  262.         }

  263.         internal ReenteranceMode RMode = ReenteranceMode.Allow;

  264.         internal Thread thread = null;

  265.         private string key = null;
  266.         public string Method { get { return key; } }

  267.         private Delegate asyncDelegate = null;
  268.         public Delegate AsyncDelegate { get { return asyncDelegate; } }

  269.         internal AsyncAction result = AsyncAction.Unknown;
  270.         public AsyncAction Result { get { return result; } }

  271.         internal Control control = null;
  272.         public Control Control { get { return control; } }

  273.         internal DateTime createTime = DateTime.Now;
  274.         public DateTime TimeCreated { get { return createTime; } }

  275.         internal DateTime completeTime = DateTime.MinValue;
  276.         public DateTime TimeCompleted { get { return completeTime; } }

  277.         internal DateTime startTime = DateTime.Now;
  278.         public DateTime TimeStarted { get { return startTime; } }

  279.         public TimeSpan TimeElapsed {
  280.             get { return ((completeTime > DateTime.MinValue) ? completeTime : DateTime.Now) - createTime; }
  281.         }

  282.         public TimeSpan TimeRunning {
  283.             get {return (startTime == DateTime.MinValue) ? TimeSpan.Zero : ((completeTime > DateTime.MinValue) ? completeTime : DateTime.Now) - startTime;}
  284.         }

  285.         internal object retVal = null;
  286.         public object ReturnValue { get { return retVal; } }

  287.         internal bool isStarted = false;
  288.         public bool IsStarted { get { return isStarted; } }

  289.         private object state = null;
  290.         public object AsyncState { get { return state; } }

  291.         /**//// <summary>
  292.         /// Aborts a running associated thread.  If possible it will cancel if not yet started
  293.         /// </summary>
  294.         /// <returns>True if the thread could be cancelled before it started.</returns>
  295.         public bool CancelOrAbort() {
  296.             isCompleted = true;
  297.             if (!isStarted) return true;//cancelled

  298.             if (thread != null && thread.IsAlive) {
  299.                 thread.Abort();
  300.             }

  301.             return false;
  302.         }

  303.         internal ManualResetEvent mre = new ManualResetEvent(false);
  304.         public WaitHandle AsyncWaitHandle { get { return mre; } }

  305.         internal bool completedSynchronously = false;
  306.         public bool CompletedSynchronously { get { return completedSynchronously; } }

  307.         internal bool isCompleted = false;
  308.         public bool IsCompleted { get { return isCompleted; } }
  309.     }
  310.     #endregion

  311.     Definitions of enums and delegates#region Definitions of enums and delegates

  312.     /**//// <summary>
  313.     /// Abreviated Empty Delegate for use in anonymous casting
  314.     /// </summary>
  315.     public delegate void Dlg();

  316.     /**//// <summary>
  317.     /// Abreviated Empty Delegate for use in anonymous methods when a return is needed
  318.     /// </summary>
  319.     /// <returns>Umm, anything you want.</returns>
  320.     public delegate object DlgR();

  321.     public enum AsyncAction {
  322.         Unknown = 0,
  323.         ThreadPool = 1,
  324.         Thread = 2,
  325.         Failed = 4,
  326.         Reenterant = 8,
  327.         ControlInvoked = 16
  328.     }

  329.     public enum ReenteranceMode {
  330.         Allow = 1,
  331.         Bypass = 2,
  332.         Stack = 4,
  333.     }
  334.     #endregion
  335. }
复制代码
异步获取控件值:
  1. AsyncRes result = Async.UI(
  2.     //make sure the delegate/method returns a value:
  3.     delegate { return textBox1.Text; },
  4.     true, //yes, we want to get the return value
  5.     myForm, //the control to invoke on
  6.     null, //the state object, we don't need to track anything.
  7.     true, //invoke asynchronously?
  8.     ReenteranceMode.Allow); //don't worry about thread safety in this case.

  9. // . do other things  //

  10. // now make sure the task above has completed.. 
  11. result.AsyncWaitHandle.WaitOne();

  12. //and use the value
  13. Console.WriteLine("The textbox says: " + result.ReturnValue);
复制代码
同步设置控件值:
  1. Async.UI(delegate { textBox1.Text = "This is way easier!"; }, textBox1, true);
复制代码
原创粉丝点击