推荐一个winform 界面交互类库

这个类库是在codeproject上发现的,主要是用于在.net 2.0,3.5的框架下,不可以在非创建线程下雨控件进行交互的限制,类库封装得比较好,使用了匿名方法。

 

ContractedBlock.gif ExpandedBlockStart.gif 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!

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Windows.Forms;

ExpandedBlockStart.gifContractedBlock.gif
namespace CodeToast {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public static class Async {

        
static Dictionary<stringobject> methodLocks = new Dictionary<stringobject>();

ContractedSubBlock.gifExpandedSubBlockStart.gif        
Async 'Do' overloads, for ease of use#region Async 'Do' overloads, for ease of use
ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif        public static AsyncRes Do(DlgR d, bool getRetVal) {
            
return Do(d, getRetVal, ReenteranceMode.Allow);
        }


ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif        public static AsyncRes Do(Dlg d) {
            
return Do(d, ReenteranceMode.Allow);
        }


ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif        public static AsyncRes Do(DlgR d, bool getRetVal, ReenteranceMode rMode) {
            
return Do(d, null, getRetVal, nulltrue, rMode, nulltrue);
        }


ExpandedSubBlockStart.gifContractedSubBlock.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="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.gifContractedSubBlock.gif        public static AsyncRes Do(Dlg d, ReenteranceMode rMode) {
            
return Do(null, d, falsenulltrue, rMode, nulltrue);
        }


ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif        public static AsyncRes Do(DlgR d, bool getRetVal, object state, bool tryThreadPool, ReenteranceMode rMode) {
            
return Do(d, null, getRetVal, state, tryThreadPool, rMode, nulltrue);
        }


ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif        public static AsyncRes Do(Dlg d, object state, bool tryThreadPool, ReenteranceMode rMode) {
            
return Do(null, d, false, state, tryThreadPool, rMode, nulltrue);
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
The Big Main private 'Do' method - called by all overloads.#region The Big Main private 'Do' method - called by all overloads.
ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.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);

            
//Create a delegate wrapper for what we will actually invoke..
ExpandedSubBlockStart.gifContractedSubBlock.gif
            Dlg dlg = (Dlg)delegate {
                
if (!BeforeInvoke(res)) return//checks for reentrance issues and sets us up
ExpandedSubBlockStart.gifContractedSubBlock.gif
                try {
                    
if (res.IsCompleted) return;
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
if (dr != null{
                        res.retVal 
= dr();//use this one if theres a return
ExpandedSubBlockStart.gifContractedSubBlock.gif
                    }
 else {
                        d();
//otherwise the simpler dlg
                    }

ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif                }
 finally {
                    FinishInvoke(res);
//this will fire our callback if they used it, and clean up
                }

            }
;

ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (control != null{
                res.control 
= control;
                res.result 
= AsyncAction.ControlInvoked;
ExpandedSubBlockStart.gifContractedSubBlock.gif                
if (!async) {
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
if (!control.InvokeRequired) {
                        res.completedSynchronously 
= true;
                        dlg();
ExpandedSubBlockStart.gifContractedSubBlock.gif                    }
 else {
                        control.Invoke(dlg);
                    }

ExpandedSubBlockStart.gifContractedSubBlock.gif                }
 else {
                    control.BeginInvoke(dlg);
                }

                
return res;
            }
 //don't catch these errors - if this fails, we shouldn't try a real thread or threadpool!

ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (tryThreadPool) //we are going to use the .NET threadpool
ExpandedSubBlockStart.gifContractedSubBlock.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);

                    
//check for at least our thread plus one more in ThreadPool
ExpandedSubBlockStart.gifContractedSubBlock.gif
                    if (threads > minThreads) {
                        
//this is what actually fires this task off..
ExpandedSubBlockStart.gifContractedSubBlock.gif
                        bool result = ThreadPool.QueueUserWorkItem((WaitCallback)delegate { dlg(); });
ExpandedSubBlockStart.gifContractedSubBlock.gif                        
if (result) {
                            res.result 
= AsyncAction.ThreadPool;
                            
//this means success in queueing and running the item
                            return res;
ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif                    }
 else {
                        Console.WriteLine(String.Format(
"Insufficient idle threadpool threads: {0} of {1} - min {2}, Method: {3}", threads, totalThreads, minThreads, key));
                    }

ExpandedSubBlockStart.gifContractedSubBlock.gif                }
 catch (Exception ex) {
                    Console.WriteLine(
"Failed to queue in threadpool: " + ex.Message, "Method: " + key);
                }

            }


            
//if we got this far, then something up there failed, or they wanted a dedicated thread
ExpandedSubBlockStart.gifContractedSubBlock.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();

            
return res;
        }

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
Before and after - helper methods#region Before and after - helper methods

ExpandedSubBlockStart.gifContractedSubBlock.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
ExpandedSubBlockStart.gifContractedSubBlock.gif
            if (res.RMode != ReenteranceMode.Allow) {
                
//be threadsafe with our one and only member field
ExpandedSubBlockStart.gifContractedSubBlock.gif
                lock (methodLocks) {
ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif
                    if (res.RMode == ReenteranceMode.Bypass) {
ExpandedSubBlockStart.gifContractedSubBlock.gif                        
if (!Monitor.TryEnter(methodLocks[res.Method])) {
                            res.result 
= AsyncAction.Reenterant;
                            
return false;
                        }

ExpandedSubBlockStart.gifContractedSubBlock.gif                    }
 else {
                        
//Otherwise in 'stack' mode, we just wait until someone else releases it
                        Monitor.Enter(methodLocks[res.Method]);
                    }


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

            }


            
return true;
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
private static void FinishInvoke(AsyncRes res) {
            
if (res == nullreturn;
ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif            }
 catch (Exception ex) {
                Console.WriteLine(
"Error setting wait handle on " + (res.Method ?? "NULL"+ ex);
            }


ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (res.RMode != ReenteranceMode.Allow) {
                
//if mode is bypass or stack, then we must have a lock that needs releasing
ExpandedSubBlockStart.gifContractedSubBlock.gif
                try {
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
if (methodLocks.ContainsKey(res.Method)) {
                        Monitor.Exit(methodLocks[res.Method]);
                    }

ExpandedSubBlockStart.gifContractedSubBlock.gif                }
 catch (Exception ex) {
                    Console.WriteLine(
"Error releasing reentrant lock on " + (res.Method ?? "NULL")+ ex);
                }

            }

        }


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
UI Overloads#region UI Overloads
ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif        public static AsyncRes UI(Dlg d, Control c, bool async) {
            
return Do(null, d, falsenullfalse, ReenteranceMode.Allow, c, async);
        }


ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif        public static AsyncRes UI(DlgR d, bool getRetVal, Control c, bool async) {
            
return Do(d, null, getRetVal, nullfalse, ReenteranceMode.Allow, c, async);
        }


ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.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

    }


ContractedSubBlock.gifExpandedSubBlockStart.gif    
AsyncRes class#region AsyncRes class
ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif    public class AsyncRes : IAsyncResult {

ExpandedSubBlockStart.gifContractedSubBlock.gif        
internal AsyncRes(object state, Delegate d, string key, ReenteranceMode rMode) {
            
this.state = state;
            
this.asyncDelegate = d;
            
this.key = key;
            
this.RMode = rMode;
        }


        
internal ReenteranceMode RMode = ReenteranceMode.Allow;

        
internal Thread thread = null;

        
private string key = null;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public string Method get return key; } }

        
private Delegate asyncDelegate = null;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public Delegate AsyncDelegate get return asyncDelegate; } }

        
internal AsyncAction result = AsyncAction.Unknown;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public AsyncAction Result get return result; } }

        
internal Control control = null;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public Control Control get return control; } }

        
internal DateTime createTime = DateTime.Now;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public DateTime TimeCreated get return createTime; } }

        
internal DateTime completeTime = DateTime.MinValue;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public DateTime TimeCompleted get return completeTime; } }

        
internal DateTime startTime = DateTime.Now;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public DateTime TimeStarted get return startTime; } }

ExpandedSubBlockStart.gifContractedSubBlock.gif        
public TimeSpan TimeElapsed {
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get return ((completeTime > DateTime.MinValue) ? completeTime : DateTime.Now) - createTime; }
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
public TimeSpan TimeRunning {
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get {return (startTime == DateTime.MinValue) ? TimeSpan.Zero : ((completeTime > DateTime.MinValue) ? completeTime : DateTime.Now) - startTime;}
        }


        
internal object retVal = null;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public object ReturnValue get return retVal; } }

        
internal bool isStarted = false;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public bool IsStarted get return isStarted; } }

        
private object state = null;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public object AsyncState get return state; } }

ExpandedSubBlockStart.gifContractedSubBlock.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.gifContractedSubBlock.gif        public bool CancelOrAbort() {
            isCompleted 
= true;
            
if (!isStarted) return true;//cancelled

ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (thread != null && thread.IsAlive) {
                thread.Abort();
            }


            
return false;
        }


        
internal ManualResetEvent mre = new ManualResetEvent(false);
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public WaitHandle AsyncWaitHandle get return mre; } }

        
internal bool completedSynchronously = false;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public bool CompletedSynchronously get return completedSynchronously; } }

        
internal bool isCompleted = false;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public bool IsCompleted get return isCompleted; } }
    }

    
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif    
Definitions of enums and delegates#region Definitions of enums and delegates

ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
    
/// Abreviated Empty Delegate for use in anonymous casting
    
/// </summary>

    public delegate void Dlg();

ExpandedSubBlockStart.gifContractedSubBlock.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();

ExpandedSubBlockStart.gifContractedSubBlock.gif    
public enum AsyncAction {
        Unknown 
= 0,
        ThreadPool 
= 1,
        Thread 
= 2,
        Failed 
= 4,
        Reenterant 
= 8,
        ControlInvoked 
= 16
    }


ExpandedSubBlockStart.gifContractedSubBlock.gif    
public enum ReenteranceMode {
        Allow 
= 1,
        Bypass 
= 2,
        Stack 
= 4,
    }

    
#endregion

}

异步获取控件值:

ContractedBlock.gif ExpandedBlockStart.gif Code
AsyncRes result = Async.UI(
    
//make sure the delegate/method returns a value:
ExpandedBlockStart.gifContractedBlock.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.

// . do other things  //

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

//and use the value
Console.WriteLine("The textbox says: " + result.ReturnValue);

 

同步设置控件值: 

ContractedBlock.gif ExpandedBlockStart.gif Code
Async.UI(delegate { textBox1.Text = "This is way easier!"; }, textBox1, true);

 


 

ModernUI(http://mui.codeplex.com/)是一个开源的WPF界面库,利用该界面库,我们可以创建很酷的应用程序。下面是ModernUI官方示例,你可以从官方网站直接下载源码运行,如果是.NET 4.0的话,记得要声明“NET4”预编译变量,否则无法编译通过。 这个界面框架是基于ModernUI来实现的,在该文我将分享所有的源码,并详细描述如何基于ModernUI来构造一个非常通用的、插件化的WPF开发框架。下载源码的同志,希望点击一下推荐。 本文将按照以下四点来介绍: (1)ModernUI简介; (2)构建通用界面框架的思路; (3)基于ModernUI和OSGi.NET的插件化界面框架实现原理及源码分析; (4)其它更有趣的东西~~。 要编写这样的WPF界面,我们需要在一个Window上声明菜单和Tab页面,下图是定义菜单的声明。 此外,每一个Tab风格页面,你也需要手动的为菜单创建这样的界面元素。 直接用这样的方式来使用ModernUI,显然不太适合团队协作性的并行开发,因为在一个团队的协作中,不同的人需要完成不同的功能,实现不同页面,每个人都需要来更改主界面。 我非常希望模块化的开发方法,因为这可以尽可能的复用现有资产,使程序员可以聚焦在自己关注的业务逻辑上,不需要关心UI的使用。下面,我将来描述基于ModernUI实现的一个通用界面框架,这个界面框架允许程序员在自己的业务模块中配置需要显示的界面元素。 通用界面框架实现思路: 我希望能够实现这样的通用界面框架: (1)程序员可以直接实现需要展现业务逻辑的界面,不需要关注如何使用ModernUI; (2)程序员可以通过简单的配置就可以将自己实现的业务逻辑页面显示在主界面中; (3)这个界面框架可以完全复用。 当我看到ModernUI这个界面库时,我希望将应用程序做成模块化,每一个模块能够: (1)通过以下配置能够直接显示二级菜单。 (2)通过以下配置能够直接显示三级菜单。 这样做的好处是,开发插件的时候可以不需要关心界面框架插件;团队在协作开发应用的时候,可以独立开发并不需要修改主界面;团队成员的插件可以随时集成到这个主界面;当主界面无法满足我们的布局时或者用户需求无法满足时,可以直接替换主界面框架而不需要修改任何插件代码。 最终的效果如下,以下界面的几个菜单及点击菜单显示的内容由DemoPlugin插件、DemoPlugin2插件来提供。当插件框架加载更多插件时,界面上会出现更多的菜单;反之,当插件被卸载或者被停止时,则相应的菜单将消失掉。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值