├── .gitattributes ├── .gitignore ├── AOPDemo ├── AOPDemo.csproj ├── App_Start │ ├── FilterConfig.cs │ ├── RouteConfig.cs │ └── WebApiConfig.cs ├── Common │ ├── AdviceAbstract.cs │ ├── AdviceAttribute.cs │ ├── AutowiredAttribute.cs │ ├── DelayProxy.cs │ ├── DelayProxyUtil.cs │ ├── MyAdvice.cs │ ├── ReflectionUtil.cs │ ├── ServiceAbstract.cs │ ├── ServiceAdviceAbstract.cs │ └── ServiceExecption.cs ├── Controllers │ └── HomeController.cs ├── Global.asax ├── Global.asax.cs ├── Properties │ └── AssemblyInfo.cs ├── Views │ ├── Home │ │ └── Index.cshtml │ └── Web.config ├── Web.Debug.config ├── Web.Release.config ├── Web.config └── packages.config ├── BlogsDemo.sln ├── CaptureWindowDemo ├── App.xaml ├── App.xaml.cs ├── CaptureWindowDemo.csproj ├── CaptureWindowHelper.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs └── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── DropDownCustomColorPicker.Test ├── App.xaml ├── App.xaml.cs ├── DropDownCustomColorPicker.Test.csproj ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings └── readme.txt ├── DropDownCustomColorPicker ├── ColorPicker.xaml ├── ColorPicker.xaml.cs ├── ColorToSolidColorBrushConverter.cs ├── CustomColorPicker.xaml ├── CustomColorPicker.xaml.cs ├── CustomColors.cs ├── DropDownCustomColorPicker.csproj ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Resources │ └── image.png └── readme.txt ├── ParallelDemo ├── App.config ├── App.xaml ├── App.xaml.cs ├── Demo │ ├── AbstractClass.cs │ ├── AtomicityClass.cs │ ├── AwaitAsyncClass.cs │ ├── ConcurrentCollectionClass.cs │ ├── InterlockedSpinLockClass.cs │ ├── LockMonitorClass.cs │ ├── PLinqClass.cs │ ├── ParallelClass.cs │ ├── ReaderWriterLockSlimClass.cs │ ├── TaskClass.cs │ ├── ThreadPoolClass.cs │ └── VariableCapturingClass.cs ├── IView.cs ├── IViewExtension.cs ├── ParallelDemo.csproj ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Window1.xaml └── Window1.xaml.cs ├── PluginDemo.NewDomain ├── NonMarshalByRefObject.cs ├── NonMarshalByRefObjectAction.cs ├── Plugin.cs ├── PluginDemo.NewDomain.csproj └── Properties │ └── AssemblyInfo.cs ├── PluginDemo ├── App.xaml ├── App.xaml.cs ├── IPlugin.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── PluginDemo.csproj └── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings └── readme.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | -------------------------------------------------------------------------------- /AOPDemo/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace AOPDemo 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /AOPDemo/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace AOPDemo 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /AOPDemo/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Http; 5 | 6 | namespace AOPDemo 7 | { 8 | public static class WebApiConfig 9 | { 10 | public static void Register(HttpConfiguration config) 11 | { 12 | config.Routes.MapHttpRoute( 13 | name: "DefaultApi", 14 | routeTemplate: "api/{controller}/{id}", 15 | defaults: new { id = RouteParameter.Optional } 16 | ); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AOPDemo/Common/AdviceAbstract.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Runtime.Remoting.Messaging; 6 | using System.Runtime.Remoting.Proxies; 7 | 8 | namespace AOPDemo.Common 9 | { 10 | /// 11 | /// 抽象的增强类 12 | /// 13 | public abstract class AdviceAbstract 14 | { 15 | public abstract IMessage Invoke(MarshalByRefObject target, IMethodCallMessage callMessage); 16 | } 17 | } -------------------------------------------------------------------------------- /AOPDemo/Common/AdviceAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace AOPDemo.Common 7 | { 8 | /// 9 | /// 为方法标记指定的增强对象 10 | /// 指定的增强,可通过代理 DelayProxy 织入 11 | /// 12 | [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] 13 | public sealed class AdviceAttribute : Attribute 14 | { 15 | /// 16 | /// 增强对象 17 | /// 18 | public AdviceAbstract Advice { get; private set; } 19 | 20 | /// 21 | /// 使用指定类型的默认增强对象 22 | /// 如果类型为空 则不使用任何增强 23 | /// 24 | /// 25 | public AdviceAttribute(Type type) 26 | : this(type, string.Empty) 27 | { 28 | 29 | } 30 | 31 | /// 32 | /// 使用公有静态方法名初始化指定类型的增强对象 33 | /// 如果类型为空 则不使用任何增强 34 | /// 35 | /// 类型 36 | /// 37 | /// 公有静态方法名 38 | /// 如果方法名为空,调用默认构造函数 39 | /// 40 | public AdviceAttribute(Type type, string methodName) 41 | { 42 | // 如果类型为空 则不使用任何增强 43 | if (type == null) 44 | { 45 | this.Advice = null; 46 | return; 47 | } 48 | 49 | if (string.IsNullOrWhiteSpace(methodName)) 50 | { 51 | this.Advice = Activator.CreateInstance(type) as AdviceAbstract; 52 | return; 53 | } 54 | 55 | this.Advice = type.InvokeMember( 56 | methodName, 57 | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public 58 | | System.Reflection.BindingFlags.Static, 59 | null, null, null) as AdviceAbstract; 60 | } 61 | 62 | 63 | 64 | 65 | 66 | #region 以下两种方式效果不是很好,不推荐使用,故 构造函数私有化 67 | 68 | /// 69 | /// 使用参数列表初始化指定类型的增强对象 70 | /// 71 | /// 类型 72 | /// 参数列表 73 | private AdviceAttribute(Type type, params object[] objs) 74 | { 75 | this.Advice = Activator.CreateInstance(type, objs) as AdviceAbstract; 76 | } 77 | 78 | /// 79 | /// 使用命名参数初始化指定类型的增强对象 80 | /// 81 | /// 82 | /// 以 冒号 和 分号 分割的形参的命名参数列表 83 | /// 支持的数据类型有:string, int, bool 及 可通过静态方法Parse 反序列化的类型 84 | /// 85 | /// 86 | private AdviceAttribute(string namedParameter, Type type) 87 | { 88 | this.Advice = ReflectionUtil.InvokeConstructor(type, namedParameter) as AdviceAbstract; 89 | } 90 | 91 | #endregion 92 | 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /AOPDemo/Common/AutowiredAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace AOPDemo.Common 7 | { 8 | /// 9 | /// 标记需要自动装配的属性 10 | /// 为属性对象启用代理,并延迟初始化被代理的对象 11 | /// 12 | [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] 13 | public sealed class AutowiredAttribute : Attribute 14 | { 15 | /// 16 | /// 是否启用代理 17 | /// True: 启用代理(延迟初始化), False: 不启用代理(不延迟初始化) 18 | /// 默认值True 19 | /// 20 | public bool UseProxy { get; private set; } 21 | 22 | 23 | /// 24 | /// 为属性对象启用代理,并延迟初始化被代理的对象 25 | /// 26 | public AutowiredAttribute() 27 | : this(true) 28 | { 29 | 30 | } 31 | 32 | /// 33 | /// 使用指定参数初始化 Attribute 34 | /// 35 | /// True: 启用代理(延迟初始化), False: 不启用代理(不延迟初始化) 36 | public AutowiredAttribute(bool useProxy) 37 | { 38 | this.UseProxy = useProxy; 39 | } 40 | 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /AOPDemo/Common/DelayProxy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Runtime.Remoting.Messaging; 6 | using System.Runtime.Remoting.Proxies; 7 | using System.Runtime.Remoting.Channels; 8 | 9 | namespace AOPDemo.Common 10 | { 11 | /// 12 | /// 支持泛型、支持延迟初始化的代理类, 可为 MarshalByRefObject 的子类型提供代理 13 | /// 在执行代理的过程中,获取 AdviceAttribute 所指定的增强,并织入该增强 14 | /// 15 | public class DelayProxy : RealProxy where T : MarshalByRefObject 16 | { 17 | private static object objLock = new object(); 18 | 19 | /// 20 | /// 被代理的对象 21 | /// 22 | private T target; 23 | 24 | /// 25 | /// 是否延迟初始化 26 | /// True:延迟, False: 不延迟 27 | /// 28 | private readonly bool delay; 29 | 30 | public DelayProxy(T target, bool delay) 31 | : base(typeof(T)) 32 | { 33 | this.target = target; 34 | this.delay = delay; 35 | } 36 | 37 | /// 38 | /// 调用被代理对象 39 | /// 支持 out ref 参数 40 | /// 41 | /// 42 | /// 43 | public override IMessage Invoke(IMessage msg) 44 | { 45 | if (this.delay && this.target == null) 46 | { 47 | lock (objLock) 48 | { 49 | if (this.delay && this.target == null) 50 | { 51 | T instance = Activator.CreateInstance(typeof(T)) as T; 52 | 53 | // 自动装配属性 54 | // 为属性对象启用代理,并延迟初始化被代理的对象 55 | // DelayProxyUtil.AutowiredProperties(instance); 56 | 57 | this.target = instance; 58 | } 59 | } 60 | } 61 | 62 | IMethodCallMessage callMessage = (IMethodCallMessage)msg; 63 | 64 | AdviceAttribute attri = ReflectionUtil.GetCustomAttribute(callMessage.MethodBase); 65 | 66 | if (attri != null && attri.Advice != null) 67 | { 68 | return attri.Advice.Invoke(this.target, callMessage); 69 | } 70 | 71 | return DelayProxyUtil.InvokeBeProxy(this.target, callMessage); 72 | } 73 | 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /AOPDemo/Common/DelayProxyUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Runtime.Remoting.Proxies; 6 | using System.Runtime.Remoting.Messaging; 7 | using System.Reflection; 8 | 9 | namespace AOPDemo.Common 10 | { 11 | /// 12 | /// 延迟初始化代理工具类 13 | /// 14 | public static class DelayProxyUtil 15 | { 16 | /// 17 | /// 自动装配属性 18 | /// 为属性对象启用代理,并延迟初始化被代理的对象 19 | /// 20 | /// 21 | /// 22 | public static void AutowiredProperties(object obj) 23 | { 24 | if (obj == null) 25 | return; 26 | 27 | // 获取公共实例属性 28 | PropertyInfo[] infos = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); 29 | 30 | if (infos != null && infos.Length > 0) 31 | { 32 | foreach (PropertyInfo pInfo in infos) 33 | { 34 | AutowiredAttribute autoProxy = ReflectionUtil.GetCustomAttribute(pInfo); 35 | 36 | if (autoProxy == null) 37 | { 38 | continue; 39 | } 40 | 41 | object pValue = DelayProxyUtil.CreateProxy(pInfo.PropertyType, autoProxy); 42 | 43 | pInfo.SetValue(obj, pValue, null); 44 | } 45 | } 46 | } 47 | 48 | 49 | /// 50 | /// 为指定类型 创建代理 51 | /// 52 | /// 53 | public static object CreateProxy(Type type, AutowiredAttribute autoProxy) 54 | { 55 | // 为属性对象启用代理,并延迟初始化被代理的对象 56 | if (autoProxy.UseProxy) 57 | { 58 | return DelayProxyUtil.GetTransparentProxy(type, null, true); 59 | } 60 | 61 | // 不启用代理,并不延迟初始化 62 | object instance = Activator.CreateInstance(type); 63 | 64 | // 自动装配属性 65 | // 为属性对象启用代理,并延迟初始化被代理的对象 66 | DelayProxyUtil.AutowiredProperties(instance); 67 | 68 | return instance; 69 | } 70 | 71 | 72 | /// 73 | /// 调用被代理对象中方法,返回 被代理对象的 方法返回值 74 | /// 支持 out ref 参数 75 | /// 76 | /// 77 | /// 78 | /// 79 | public static IMessage InvokeBeProxy(MarshalByRefObject target, IMethodCallMessage callMessage) 80 | { 81 | var args = callMessage.Args; 82 | 83 | object returnValue = callMessage.MethodBase.Invoke(target, args); 84 | 85 | return new ReturnMessage(returnValue, args, args.Length, callMessage.LogicalCallContext, callMessage); 86 | } 87 | 88 | /// 89 | /// 返回方法默认值 90 | /// 91 | /// 92 | /// 93 | /// 94 | public static IMessage ReturnDefaultValue(MarshalByRefObject target, IMethodCallMessage callMessage) 95 | { 96 | MethodInfo info = callMessage.MethodBase as MethodInfo; 97 | 98 | object returnValue = info.ReturnType == typeof(void) ? null : ReflectionUtil.GetDefaultValue(info.ReturnType); 99 | 100 | return new ReturnMessage(returnValue, null, 0, callMessage.LogicalCallContext, callMessage); 101 | } 102 | 103 | /// 104 | /// 向上层抛出异常 105 | /// 106 | /// 107 | /// 108 | /// 109 | public static IMessage ReturnExecption(Exception ex, IMethodCallMessage callMessage) 110 | { 111 | return new ReturnMessage(ex, callMessage); 112 | } 113 | 114 | 115 | 116 | 117 | 118 | /// 119 | /// 获取对象的代理 120 | /// 121 | /// 该类型必须为 ServiceAbstract 类型的子类 122 | /// 123 | /// 124 | /// 125 | private static object GetTransparentProxy(Type type, object instance, bool delay) 126 | { 127 | if (!type.IsSubclassOf(typeof(MarshalByRefObject))) 128 | { 129 | throw new Exception("所代理的对象的类型必须为 ServiceAbstract 类型的子类"); 130 | } 131 | 132 | Type tmpType = typeof(DelayProxy<>); 133 | 134 | tmpType = tmpType.MakeGenericType(type); 135 | 136 | RealProxy proxy = Activator.CreateInstance(tmpType, new object[] { instance, delay }) as RealProxy; 137 | 138 | return proxy.GetTransparentProxy(); 139 | } 140 | 141 | 142 | } 143 | 144 | } -------------------------------------------------------------------------------- /AOPDemo/Common/MyAdvice.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Runtime.Remoting.Messaging; 6 | using System.Runtime.Remoting.Proxies; 7 | 8 | namespace AOPDemo.Common 9 | { 10 | public class MyAdvice : ServiceAdviceAbstract 11 | { 12 | /// 13 | /// 14 | /// 15 | /// 是否保持(长)连接,即自动管理连接 16 | /// 是否使用事务,即自动管理事务 17 | public MyAdvice(bool keepConnection, bool useTransaction) 18 | : base(keepConnection, useTransaction) 19 | { 20 | 21 | } 22 | 23 | 24 | 25 | /// 26 | /// 保持连接 27 | /// 28 | /// 29 | public static MyAdvice GetKeepConnection() 30 | { 31 | return new MyAdvice(true, false); 32 | } 33 | 34 | /// 35 | /// 开启事务 36 | /// 37 | /// 38 | public static MyAdvice GetUseTransaction() 39 | { 40 | return new MyAdvice(true, true); 41 | } 42 | 43 | 44 | 45 | #region Override 46 | 47 | protected override void OpenConnection() 48 | { 49 | Console.WriteLine("打开连接"); 50 | } 51 | 52 | protected override void CloseConnection() 53 | { 54 | Console.WriteLine("关闭连接"); 55 | } 56 | 57 | protected override void BeginTransaction(bool onlyBeginTransaction) 58 | { 59 | Console.WriteLine("开启事务"); 60 | } 61 | 62 | protected override void CommitTransaction(bool onlyCommitTransaction) 63 | { 64 | Console.WriteLine("提交事务"); 65 | } 66 | 67 | protected override void RollBackTransaction(bool onlyRollBackTransaction) 68 | { 69 | Console.WriteLine("回滚事务"); 70 | } 71 | 72 | protected override bool HasOpenConnection() 73 | { 74 | Console.WriteLine("打开连接"); 75 | // TODO 76 | return false; 77 | } 78 | 79 | protected override bool HasBeginTransaction() 80 | { 81 | Console.WriteLine("开启事务"); 82 | // TODO 83 | return false; 84 | } 85 | 86 | #endregion 87 | 88 | } 89 | } -------------------------------------------------------------------------------- /AOPDemo/Common/ServiceAbstract.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace AOPDemo.Common 7 | { 8 | 9 | /// 10 | /// 扩展的抽象服务类 11 | /// 配合增强类,完成以下功能: 12 | /// 1、自动管理数据库连接[可选] 13 | /// 2、自动管理数据库事务,当接收到异常后(无论什么异常)事务将自动回滚[可选] 14 | /// 15 | /// 3、服务级加锁[必选] 16 | /// 4、以统一方式处理服务异常及错误处理,包括数据库异常 和 主动抛出的异常[必选] 17 | /// 18 | public abstract class ServiceAbstract : MarshalByRefObject 19 | { 20 | /// 21 | /// 是否发生错误 22 | /// 23 | public bool Error { get; protected set; } 24 | 25 | /// 26 | /// 错误提示信息(友好的,用户可见) 27 | /// 28 | public string ErrorMsg { get; protected set; } 29 | 30 | /// 31 | /// 错误详情 32 | /// 所有错误,均通过异常抛出 33 | /// 34 | public Exception ErrorEx { get; protected set; } 35 | 36 | 37 | 38 | /// 39 | /// 重置错误信息 40 | /// 41 | public void ResetError() 42 | { 43 | this.Error = false; 44 | this.ErrorMsg = string.Empty; 45 | this.ErrorEx = null; 46 | } 47 | 48 | /// 49 | /// 设置错误信息 50 | /// 51 | /// 52 | /// 53 | public void SetError(string msg, Exception ex) 54 | { 55 | this.Error = true; 56 | this.ErrorEx = ex; 57 | this.ErrorMsg = msg; 58 | } 59 | 60 | 61 | /// 62 | /// 获取服务级别的锁定对象,以完成系统应用层加锁(具体而言是Service层加锁) 63 | /// 64 | /// 65 | public abstract object GetLockObject(); 66 | 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /AOPDemo/Common/ServiceExecption.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace AOPDemo.Common 7 | { 8 | 9 | /// 10 | /// 自定义的服务异常 11 | /// 12 | [Serializable] 13 | public class ServiceException : Exception 14 | { 15 | /// 16 | /// 为异常提供附加数据 17 | /// 用户不可见 18 | /// 19 | public int Code { get; set; } 20 | 21 | /// 22 | /// 为异常提供附加数据 23 | /// 用户不可见 24 | /// 25 | public string Tag { get; set; } 26 | 27 | public ServiceException() { } 28 | public ServiceException(string message) : base(message) { } 29 | public ServiceException(string message, Exception inner) : base(message, inner) { } 30 | protected ServiceException( 31 | System.Runtime.Serialization.SerializationInfo info, 32 | System.Runtime.Serialization.StreamingContext context) 33 | : base(info, context) { } 34 | } 35 | 36 | 37 | } -------------------------------------------------------------------------------- /AOPDemo/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using AOPDemo.Common; 7 | 8 | namespace AOPDemo.Controllers 9 | { 10 | public class HomeController : Controller 11 | { 12 | /// 13 | /// 使用 Autowired Attribute 自动初始化代理对象 14 | /// 15 | [Autowired] 16 | public Service myService { get; set; } 17 | 18 | 19 | public ActionResult Index() 20 | { 21 | myService.Test(); 22 | 23 | var msg = myService.ErrorMsg; 24 | Console.WriteLine(msg); 25 | 26 | // 当然 ServiceException 中的 Code属性也可以存储在 ServiceAbstract 对象中 27 | 28 | return View(); 29 | } 30 | } 31 | 32 | 33 | public class Service : ServiceAbstract 34 | { 35 | #region 自动加锁 36 | 37 | private static object objLock = new object(); 38 | 39 | public override object GetLockObject() 40 | { 41 | return objLock; 42 | } 43 | 44 | #endregion 45 | 46 | 47 | /// 48 | /// 自动开启事务 49 | /// 50 | [Advice(typeof(MyAdvice), "GetUseTransaction")] 51 | public void Test() 52 | { 53 | Console.WriteLine("调用Test方法,在调用方法前开启事务,调用方法后提交或回滚事务"); 54 | 55 | throw new ServiceException("发生异常,回滚事务") { Code = 999 }; 56 | } 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /AOPDemo/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="AOPDemo.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /AOPDemo/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Http; 6 | using System.Web.Http.Dispatcher; 7 | using System.Web.Http.Controllers; 8 | using System.Net.Http; 9 | using System.Web.Mvc; 10 | using System.Web.Routing; 11 | using AOPDemo.Common; 12 | 13 | namespace AOPDemo 14 | { 15 | // Note: For instructions on enabling IIS6 or IIS7 classic mode, 16 | // visit http://go.microsoft.com/?LinkId=9394801 17 | public class MvcApplication : System.Web.HttpApplication 18 | { 19 | protected void Application_Start() 20 | { 21 | // 注册新的Controller工厂 22 | ControllerBuilder.Current.SetControllerFactory(new MyBatisControllerFactory()); 23 | 24 | // 使AOP适应 WebApi 25 | GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new MyHttpControllerActivator()); 26 | 27 | AreaRegistration.RegisterAllAreas(); 28 | 29 | WebApiConfig.Register(GlobalConfiguration.Configuration); 30 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 31 | RouteConfig.RegisterRoutes(RouteTable.Routes); 32 | } 33 | 34 | 35 | 36 | private class MyBatisControllerFactory : DefaultControllerFactory 37 | { 38 | public override IController CreateController(RequestContext requestContext, string controllerName) 39 | { 40 | IController controller = base.CreateController(requestContext, controllerName); 41 | 42 | /// 自动装配属性 43 | /// 为属性对象启用代理,并延迟初始化被代理的对象 44 | DelayProxyUtil.AutowiredProperties(controller); 45 | 46 | return controller; 47 | } 48 | } 49 | 50 | 51 | 52 | /// 53 | /// 用于Web Api 54 | /// 55 | private class MyHttpControllerActivator : IHttpControllerActivator 56 | { 57 | private DefaultHttpControllerActivator defaultActivator; 58 | 59 | public MyHttpControllerActivator() 60 | { 61 | this.defaultActivator = new DefaultHttpControllerActivator(); 62 | } 63 | 64 | public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) 65 | { 66 | IHttpController httpController = this.defaultActivator.Create(request, controllerDescriptor, controllerType); 67 | 68 | if (httpController != null) 69 | { 70 | /// 自动装配属性 71 | /// 为属性对象启用代理,并延迟初始化被代理的对象 72 | DelayProxyUtil.AutowiredProperties(httpController); 73 | } 74 | 75 | return httpController; 76 | } 77 | } 78 | 79 | 80 | } 81 | 82 | 83 | 84 | } -------------------------------------------------------------------------------- /AOPDemo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息通过下列特性集 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("AOPDemo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("AOPDemo")] 13 | [assembly: AssemblyCopyright("版权所有(C) Microsoft 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的某个类型, 19 | // 请针对该类型将 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("aafe6fea-5f28-4cb1-825d-413959df74ca")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 内部版本号 30 | // 修订号 31 | // 32 | // 可以指定所有这些值,也可以使用“修订号”和“内部版本号”的默认值, 33 | // 方法是按如下所示使用“*”: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /AOPDemo/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Index"; 3 | } 4 | 5 |

本Demo使用RealProxy实现了简单的AOP

6 |

此外,自定义了AutowiredAttribute,标记该属性会自动初始化,当然也支持延迟初始化

7 |

自己实现简单的AOP(一)简介

8 |

自己实现简单的AOP(二)引入Attribute 为方法指定增强对象

9 |

自己实现简单的AOP(三) 实现增强四项基本功能

10 |

自己实现简单的AOP(四)自动初始化代理对象

11 |

自己实现简单的AOP(五)使Demo适应webApi、亦可完成属性自动注入

12 | 13 | -------------------------------------------------------------------------------- /AOPDemo/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /AOPDemo/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /AOPDemo/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /AOPDemo/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /AOPDemo/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /BlogsDemo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NET", "NET", "{9125DCFF-2041-40FA-8B4D-D19EB77F7B24}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WPF", "WPF", "{942427F4-3BE9-49F4-9084-86CE08406A89}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WinForm", "WinForm", "{86F3FF10-931E-4B6C-B114-F4305A9E3E3C}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParallelDemo", "ParallelDemo\ParallelDemo.csproj", "{6D3C0CF4-4029-4E7A-A33E-B0D038B3BF92}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginDemo", "PluginDemo\PluginDemo.csproj", "{803E039B-BF06-4D35-966F-0BC4A96D4A98}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AOPDemo", "AOPDemo\AOPDemo.csproj", "{04412CBA-9B27-4A99-BEA9-8432CB370055}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginDemo.NewDomain", "PluginDemo.NewDomain\PluginDemo.NewDomain.csproj", "{60D4EE42-C507-41B3-ADF5-432AD02A6FED}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DropDownCustomColorPicker", "DropDownCustomColorPicker\DropDownCustomColorPicker.csproj", "{FD2EC7D4-4316-4F8F-8108-8381F0B4B340}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DropDownCustomColorPicker.Test", "DropDownCustomColorPicker.Test\DropDownCustomColorPicker.Test.csproj", "{46B3AA45-E0B3-4D68-B91A-878D2DA7A0C9}" 23 | EndProject 24 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B8C7778C-C449-4D34-86C1-6AA314A3AC84}" 25 | ProjectSection(SolutionItems) = preProject 26 | readme.txt = readme.txt 27 | EndProjectSection 28 | EndProject 29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CaptureWindowDemo", "CaptureWindowDemo\CaptureWindowDemo.csproj", "{5F8BE534-08E0-488A-B2A6-DA301C3E91FA}" 30 | EndProject 31 | Global 32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 33 | Debug|Any CPU = Debug|Any CPU 34 | Release|Any CPU = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 37 | {6D3C0CF4-4029-4E7A-A33E-B0D038B3BF92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {6D3C0CF4-4029-4E7A-A33E-B0D038B3BF92}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {6D3C0CF4-4029-4E7A-A33E-B0D038B3BF92}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {6D3C0CF4-4029-4E7A-A33E-B0D038B3BF92}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {803E039B-BF06-4D35-966F-0BC4A96D4A98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {803E039B-BF06-4D35-966F-0BC4A96D4A98}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {803E039B-BF06-4D35-966F-0BC4A96D4A98}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {803E039B-BF06-4D35-966F-0BC4A96D4A98}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {04412CBA-9B27-4A99-BEA9-8432CB370055}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {04412CBA-9B27-4A99-BEA9-8432CB370055}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {04412CBA-9B27-4A99-BEA9-8432CB370055}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {04412CBA-9B27-4A99-BEA9-8432CB370055}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {60D4EE42-C507-41B3-ADF5-432AD02A6FED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {60D4EE42-C507-41B3-ADF5-432AD02A6FED}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {60D4EE42-C507-41B3-ADF5-432AD02A6FED}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {60D4EE42-C507-41B3-ADF5-432AD02A6FED}.Release|Any CPU.Build.0 = Release|Any CPU 53 | {FD2EC7D4-4316-4F8F-8108-8381F0B4B340}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 54 | {FD2EC7D4-4316-4F8F-8108-8381F0B4B340}.Debug|Any CPU.Build.0 = Debug|Any CPU 55 | {FD2EC7D4-4316-4F8F-8108-8381F0B4B340}.Release|Any CPU.ActiveCfg = Release|Any CPU 56 | {FD2EC7D4-4316-4F8F-8108-8381F0B4B340}.Release|Any CPU.Build.0 = Release|Any CPU 57 | {46B3AA45-E0B3-4D68-B91A-878D2DA7A0C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 58 | {46B3AA45-E0B3-4D68-B91A-878D2DA7A0C9}.Debug|Any CPU.Build.0 = Debug|Any CPU 59 | {46B3AA45-E0B3-4D68-B91A-878D2DA7A0C9}.Release|Any CPU.ActiveCfg = Release|Any CPU 60 | {46B3AA45-E0B3-4D68-B91A-878D2DA7A0C9}.Release|Any CPU.Build.0 = Release|Any CPU 61 | {5F8BE534-08E0-488A-B2A6-DA301C3E91FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 62 | {5F8BE534-08E0-488A-B2A6-DA301C3E91FA}.Debug|Any CPU.Build.0 = Debug|Any CPU 63 | {5F8BE534-08E0-488A-B2A6-DA301C3E91FA}.Release|Any CPU.ActiveCfg = Release|Any CPU 64 | {5F8BE534-08E0-488A-B2A6-DA301C3E91FA}.Release|Any CPU.Build.0 = Release|Any CPU 65 | EndGlobalSection 66 | GlobalSection(SolutionProperties) = preSolution 67 | HideSolutionNode = FALSE 68 | EndGlobalSection 69 | GlobalSection(NestedProjects) = preSolution 70 | {6D3C0CF4-4029-4E7A-A33E-B0D038B3BF92} = {9125DCFF-2041-40FA-8B4D-D19EB77F7B24} 71 | {803E039B-BF06-4D35-966F-0BC4A96D4A98} = {9125DCFF-2041-40FA-8B4D-D19EB77F7B24} 72 | {04412CBA-9B27-4A99-BEA9-8432CB370055} = {9125DCFF-2041-40FA-8B4D-D19EB77F7B24} 73 | {60D4EE42-C507-41B3-ADF5-432AD02A6FED} = {9125DCFF-2041-40FA-8B4D-D19EB77F7B24} 74 | {FD2EC7D4-4316-4F8F-8108-8381F0B4B340} = {942427F4-3BE9-49F4-9084-86CE08406A89} 75 | {46B3AA45-E0B3-4D68-B91A-878D2DA7A0C9} = {942427F4-3BE9-49F4-9084-86CE08406A89} 76 | {5F8BE534-08E0-488A-B2A6-DA301C3E91FA} = {9125DCFF-2041-40FA-8B4D-D19EB77F7B24} 77 | EndGlobalSection 78 | EndGlobal 79 | -------------------------------------------------------------------------------- /CaptureWindowDemo/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /CaptureWindowDemo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Windows; 7 | 8 | namespace CaptureWindowDemo 9 | { 10 | /// 11 | /// App.xaml 的交互逻辑 12 | /// 13 | public partial class App : Application 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /CaptureWindowDemo/CaptureWindowDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {5F8BE534-08E0-488A-B2A6-DA301C3E91FA} 8 | WinExe 9 | Properties 10 | CaptureWindowDemo 11 | CaptureWindowDemo 12 | v4.0 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 4.0 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | MSBuild:Compile 55 | Designer 56 | 57 | 58 | MSBuild:Compile 59 | Designer 60 | 61 | 62 | App.xaml 63 | Code 64 | 65 | 66 | 67 | MainWindow.xaml 68 | Code 69 | 70 | 71 | 72 | 73 | Code 74 | 75 | 76 | True 77 | True 78 | Resources.resx 79 | 80 | 81 | True 82 | Settings.settings 83 | True 84 | 85 | 86 | ResXFileCodeGenerator 87 | Resources.Designer.cs 88 | 89 | 90 | SettingsSingleFileGenerator 91 | Settings.Designer.cs 92 | 93 | 94 | 95 | 96 | 103 | -------------------------------------------------------------------------------- /CaptureWindowDemo/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 31 | 32 | 33 | 34 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /CaptureWindowDemo/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | using System.Windows.Data; 8 | using System.Windows.Documents; 9 | using System.Windows.Input; 10 | using System.Windows.Media; 11 | using System.Windows.Media.Imaging; 12 | using System.Windows.Navigation; 13 | using System.Windows.Shapes; 14 | 15 | namespace CaptureWindowDemo 16 | { 17 | /// 18 | /// MainWindow.xaml 的交互逻辑 19 | /// 20 | public partial class MainWindow : Window 21 | { 22 | private IntPtr screenIntptr; 23 | private System.Drawing.Size screenSize; 24 | 25 | public MainWindow() 26 | { 27 | InitializeComponent(); 28 | 29 | this.screenIntptr = CaptureWindowHelper.User32.GetDesktopWindow(); 30 | 31 | 32 | CaptureWindowHelper.User32.RECT rect = new CaptureWindowHelper.User32.RECT(); 33 | 34 | CaptureWindowHelper.User32.GetWindowRect(this.screenIntptr, ref rect); 35 | 36 | this.screenSize = new System.Drawing.Size(rect.right - rect.left, rect.bottom - rect.top); 37 | } 38 | 39 | private void captureFull_Click(object sender, RoutedEventArgs e) 40 | { 41 | var bitmap = CaptureWindowHelper.CaptureWindow(this.screenIntptr, this.screenSize.Width, this.screenSize.Height); 42 | 43 | if (bitmap == null) 44 | return; 45 | 46 | this.img.Source = this.BitmapToBitmapImage(bitmap); 47 | } 48 | 49 | private void captureThumbnail_Click(object sender, RoutedEventArgs e) 50 | { 51 | var bitmap = CaptureWindowHelper.CaptureWindow(this.screenIntptr, this.screenSize.Width, this.screenSize.Height, this.screenSize.Width / 2, this.screenSize.Height / 2); 52 | 53 | if (bitmap == null) 54 | return; 55 | 56 | this.img.Source = this.BitmapToBitmapImage(bitmap); 57 | } 58 | 59 | 60 | private BitmapImage BitmapToBitmapImage(System.Drawing.Bitmap bitmap) 61 | { 62 | BitmapImage bitmapImage = new BitmapImage(); 63 | 64 | using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) 65 | { 66 | bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); 67 | 68 | bitmapImage.BeginInit(); 69 | bitmapImage.StreamSource = ms; 70 | bitmapImage.CacheOption = BitmapCacheOption.OnLoad; 71 | bitmapImage.EndInit(); 72 | bitmapImage.Freeze(); 73 | } 74 | 75 | // 释放资源 76 | bitmap.Dispose(); 77 | 78 | return bitmapImage; 79 | } 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /CaptureWindowDemo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // 有关程序集的一般信息由以下 8 | // 控制。更改这些特性值可修改 9 | // 与程序集关联的信息。 10 | [assembly: AssemblyTitle("CaptureWindowDemo")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("CaptureWindowDemo")] 15 | [assembly: AssemblyCopyright("Copyright © 2017")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | //将 ComVisible 设置为 false 将使此程序集中的类型 20 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 21 | //请将此类型的 ComVisible 特性设置为 true。 22 | [assembly: ComVisible(false)] 23 | 24 | //若要开始生成可本地化的应用程序,请 25 | // 中的 .csproj 文件中 26 | //例如,如果您在源文件中使用的是美国英语, 27 | //使用的是美国英语,请将 设置为 en-US。 然后取消 28 | //对以下 NeutralResourceLanguage 特性的注释。 更新 29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置 36 | //(当资源未在页面 37 | //或应用程序资源字典中找到时使用) 38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 39 | //(当资源未在页面 40 | //、应用程序或任何主题专用资源字典中找到时使用) 41 | )] 42 | 43 | 44 | // 程序集的版本信息由下列四个值组成: 45 | // 46 | // 主版本 47 | // 次版本 48 | // 生成号 49 | // 修订号 50 | // 51 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 52 | // 方法是按如下所示使用“*”: : 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /CaptureWindowDemo/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本: 4.0.30319.42000 5 | // 6 | // 对此文件的更改可能导致不正确的行为,如果 7 | // 重新生成代码,则所做更改将丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CaptureWindowDemo.Properties 12 | { 13 | 14 | 15 | /// 16 | /// 强类型资源类,用于查找本地化字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// 返回此类使用的缓存 ResourceManager 实例。 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CaptureWindowDemo.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// 覆盖当前线程的 CurrentUICulture 属性 56 | /// 使用此强类型的资源类的资源查找。 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /CaptureWindowDemo/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /CaptureWindowDemo/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CaptureWindowDemo.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CaptureWindowDemo/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Windows; 7 | 8 | namespace DropDownCustomColorPicker.Test 9 | { 10 | /// 11 | /// App.xaml 的交互逻辑 12 | /// 13 | public partial class App : Application 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/DropDownCustomColorPicker.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {46B3AA45-E0B3-4D68-B91A-878D2DA7A0C9} 8 | WinExe 9 | Properties 10 | DropDownCustomColorPicker.Test 11 | DropDownCustomColorPicker.Test 12 | v4.0 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 4.0 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | MSBuild:Compile 54 | Designer 55 | 56 | 57 | MSBuild:Compile 58 | Designer 59 | 60 | 61 | App.xaml 62 | Code 63 | 64 | 65 | MainWindow.xaml 66 | Code 67 | 68 | 69 | 70 | 71 | Code 72 | 73 | 74 | True 75 | True 76 | Resources.resx 77 | 78 | 79 | True 80 | Settings.settings 81 | True 82 | 83 | 84 | ResXFileCodeGenerator 85 | Resources.Designer.cs 86 | 87 | 88 | SettingsSingleFileGenerator 89 | Settings.Designer.cs 90 | 91 | 92 | 93 | 94 | 95 | {fd2ec7d4-4316-4f8f-8108-8381f0b4b340} 96 | DropDownCustomColorPicker 97 | 98 | 99 | 100 | 101 | 102 | 103 | 110 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | using System.Windows.Data; 8 | using System.Windows.Documents; 9 | using System.Windows.Input; 10 | using System.Windows.Media; 11 | using System.Windows.Media.Imaging; 12 | using System.Windows.Navigation; 13 | using System.Windows.Shapes; 14 | 15 | namespace DropDownCustomColorPicker.Test 16 | { 17 | /// 18 | /// MainWindow.xaml 的交互逻辑 19 | /// 20 | public partial class MainWindow : Window 21 | { 22 | public MainWindow() 23 | { 24 | InitializeComponent(); 25 | this.Loaded += Window1_Loaded; 26 | } 27 | 28 | private void Window1_Loaded(object sender, RoutedEventArgs e) 29 | { 30 | this.customCP.SelectedColor = Colors.Green; 31 | } 32 | 33 | private void customCP_SelectedColorChanged(object sender, RoutedPropertyChangedEventArgs e) 34 | { 35 | this.canPreview.Background = new SolidColorBrush((Color)e.NewValue); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // 有关程序集的一般信息由以下 8 | // 控制。更改这些特性值可修改 9 | // 与程序集关联的信息。 10 | [assembly: AssemblyTitle("DropDownCustomColorPicker.Test")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("DropDownCustomColorPicker.Test")] 15 | [assembly: AssemblyCopyright("Copyright © 2017")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | //将 ComVisible 设置为 false 将使此程序集中的类型 20 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 21 | //请将此类型的 ComVisible 特性设置为 true。 22 | [assembly: ComVisible(false)] 23 | 24 | //若要开始生成可本地化的应用程序,请 25 | // 中的 .csproj 文件中 26 | //例如,如果您在源文件中使用的是美国英语, 27 | //使用的是美国英语,请将 设置为 en-US。 然后取消 28 | //对以下 NeutralResourceLanguage 特性的注释。 更新 29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置 36 | //(当资源未在页面 37 | //或应用程序资源字典中找到时使用) 38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 39 | //(当资源未在页面 40 | //、应用程序或任何主题专用资源字典中找到时使用) 41 | )] 42 | 43 | 44 | // 程序集的版本信息由下列四个值组成: 45 | // 46 | // 主版本 47 | // 次版本 48 | // 生成号 49 | // 修订号 50 | // 51 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 52 | // 方法是按如下所示使用“*”: : 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本: 4.0.30319.42000 5 | // 6 | // 对此文件的更改可能导致不正确的行为,如果 7 | // 重新生成代码,则所做更改将丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DropDownCustomColorPicker.Test.Properties 12 | { 13 | 14 | 15 | /// 16 | /// 强类型资源类,用于查找本地化字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// 返回此类使用的缓存 ResourceManager 实例。 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DropDownCustomColorPicker.Test.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// 覆盖当前线程的 CurrentUICulture 属性 56 | /// 使用此强类型的资源类的资源查找。 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DropDownCustomColorPicker.Test.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker.Test/readme.txt: -------------------------------------------------------------------------------- 1 | 该项目源自: 2 | http://wpfcolorpicker.codeplex.com/ 3 | https://www.codeproject.com/Articles/42849/Making-a-Drop-Down-Style-Custom-Color-Picker-in-WP 4 | 5 | 但是,我已对源码做了大量修改,以适应自己的产品需求,也可以说是完善,也可以说是改进,当然也可能改“烂”了。 6 | 7 | 优化项: 8 | 1、预定义颜色的排序、视觉效果更美观 9 | 2、Expander 控件的自动折叠和展开、操作更方便。 10 | 11 | 3、优化使用鼠标选取像素点的操作,代码逻辑更简洁、操作更流畅。 12 | 4、增加了 SelectedColorChangedEvent 、 DropDownStateChangedEvent 事件 13 | 5、使用 Slider 替代了 TextBox 来修改 RGB 颜色值 14 | 15 | 6、增加了几个配置属性,使用起来更方便。 16 | 7、该项目会继续进行扩展及优化,敬请期待。 17 | 18 | 2017年5月13日 -------------------------------------------------------------------------------- /DropDownCustomColorPicker/ColorToSolidColorBrushConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Data; 6 | using System.Windows.Media; 7 | 8 | namespace DropDownCustomColorPicker 9 | { 10 | 11 | [ValueConversion(typeof(Color), typeof(Brush))] 12 | public class ColorToSolidColorBrushConverter : IValueConverter 13 | { 14 | #region IValueConverter Members 15 | 16 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 17 | { 18 | return new SolidColorBrush((Color)value); 19 | } 20 | 21 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | 26 | #endregion 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker/CustomColorPicker.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Windows; 5 | using System.Windows.Controls; 6 | using System.Windows.Data; 7 | using System.Windows.Documents; 8 | using System.Windows.Input; 9 | using System.Windows.Media; 10 | using System.Windows.Media.Imaging; 11 | using System.Windows.Navigation; 12 | using System.Windows.Shapes; 13 | using System.Windows.Controls.Primitives; 14 | 15 | namespace DropDownCustomColorPicker 16 | { 17 | /// 18 | /// Interaction logic for CustomColorPicker.xaml 19 | /// 20 | public partial class CustomColorPicker : UserControl 21 | { 22 | 23 | #region TBEvents 24 | 25 | /// 26 | /// 自定义颜色改变事件 27 | /// 28 | public static readonly RoutedEvent SelectedColorChangedEvent = 29 | EventManager.RegisterRoutedEvent("SelectedColorChanged", RoutingStrategy.Direct, typeof(RoutedPropertyChangedEventHandler), typeof(CustomColorPicker)); 30 | 31 | /// 32 | /// 自定义颜色改变事件 CLR包装器 33 | /// 34 | public event RoutedPropertyChangedEventHandler SelectedColorChanged 35 | { 36 | add { this.AddHandler(SelectedColorChangedEvent, value); } 37 | remove { this.RemoveHandler(SelectedColorChangedEvent, value); } 38 | } 39 | 40 | 41 | /// 42 | /// 自定义DropDown状态改变事件 43 | /// 44 | public static readonly RoutedEvent DropDownStateChangedEvent = 45 | EventManager.RegisterRoutedEvent("DropDownStateChanged", RoutingStrategy.Direct, typeof(RoutedPropertyChangedEventHandler), typeof(CustomColorPicker)); 46 | 47 | /// 48 | /// 自定义DropDown状态改变事件 CLR包装器 49 | /// 50 | public event RoutedPropertyChangedEventHandler DropDownStateChanged 51 | { 52 | add { this.AddHandler(DropDownStateChangedEvent, value); } 53 | remove { this.RemoveHandler(DropDownStateChangedEvent, value); } 54 | } 55 | 56 | #endregion 57 | 58 | 59 | #region DPProperties 60 | 61 | public Size ColorRectSize 62 | { 63 | get { return (Size)GetValue(ColorRectSizeProperty); } 64 | set { SetValue(ColorRectSizeProperty, value); } 65 | } 66 | 67 | public static readonly DependencyProperty ColorRectSizeProperty = 68 | DependencyProperty.Register("ColorRectSize", typeof(Size), typeof(CustomColorPicker), new PropertyMetadata(new Size(12, 12))); 69 | 70 | 71 | public PlacementMode Mode 72 | { 73 | get { return (PlacementMode)GetValue(ModeProperty); } 74 | set { SetValue(ModeProperty, value); } 75 | } 76 | 77 | public static readonly DependencyProperty ModeProperty = 78 | DependencyProperty.Register("Mode", typeof(PlacementMode), typeof(CustomColorPicker), new PropertyMetadata(PlacementMode.Bottom)); 79 | 80 | 81 | #endregion 82 | 83 | 84 | public Color SelectedColor 85 | { 86 | get 87 | { 88 | return cp.CustomColor; 89 | } 90 | set 91 | { 92 | cp.CustomColor = value; 93 | recContent.Fill = new SolidColorBrush(value); 94 | } 95 | } 96 | 97 | 98 | public CustomColorPicker() 99 | { 100 | InitializeComponent(); 101 | 102 | b.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(b_PreviewMouseLeftButtonUp); 103 | } 104 | 105 | 106 | /// 107 | /// 打开Picker 108 | /// 109 | public void OpenPicker() 110 | { 111 | // 为快捷菜单设置焦点 112 | this.b.Focus(); 113 | 114 | b_PreviewMouseLeftButtonUp(null, null); 115 | } 116 | 117 | /// 118 | /// 关闭 Picker 119 | /// 120 | public void ClosePicker() 121 | { 122 | if (b.ContextMenu != null) 123 | { 124 | b.ContextMenu.IsOpen = false; 125 | } 126 | 127 | // 转移焦点 128 | this.Focus(); 129 | this.b.Focus(); 130 | } 131 | 132 | 133 | #region Events 134 | 135 | internal void RaiseSelectedColorChangedEvent() 136 | { 137 | RoutedPropertyChangedEventArgs args = new RoutedPropertyChangedEventArgs(Colors.Transparent, cp.CustomColor, SelectedColorChangedEvent) 138 | { 139 | Source = this 140 | }; 141 | 142 | recContent.Fill = new SolidColorBrush(cp.CustomColor); 143 | this.RaiseEvent(args); 144 | } 145 | 146 | 147 | protected void RaiseDropDownStateChangedEvent(bool opened) 148 | { 149 | RoutedPropertyChangedEventArgs args = new RoutedPropertyChangedEventArgs(false, opened, DropDownStateChangedEvent) 150 | { 151 | Source = this 152 | }; 153 | 154 | this.RaiseEvent(args); 155 | } 156 | 157 | private void b_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) 158 | { 159 | if (b.ContextMenu != null) 160 | { 161 | this.cp.CustomColorPicker = this; 162 | b.ContextMenu.PlacementTarget = b; 163 | b.ContextMenu.Placement = this.Mode; 164 | ContextMenuService.SetPlacement(b, this.Mode); 165 | b.ContextMenu.IsOpen = true; 166 | } 167 | } 168 | 169 | private void ContextMenu_Closed(object sender, RoutedEventArgs e) 170 | { 171 | RaiseDropDownStateChangedEvent(false); 172 | } 173 | 174 | private void ContextMenu_Opened(object sender, RoutedEventArgs e) 175 | { 176 | RaiseDropDownStateChangedEvent(true); 177 | } 178 | 179 | #endregion 180 | 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker/CustomColors.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Windows.Media; 7 | 8 | namespace DropDownCustomColorPicker 9 | { 10 | /// 11 | /// 反射预定义颜色 12 | /// 13 | public class CustomColors 14 | { 15 | List selectableColors = null; 16 | 17 | public List SelectableColors 18 | { 19 | get { return selectableColors; } 20 | set { selectableColors = value; } 21 | } 22 | 23 | public CustomColors() 24 | { 25 | var list = new List(); 26 | 27 | Type ColorsType = typeof(Colors); 28 | PropertyInfo[] ColorsProperty = ColorsType.GetProperties(); 29 | 30 | foreach (PropertyInfo property in ColorsProperty) 31 | { 32 | list.Add((Color)ColorConverter.ConvertFromString(property.Name)); 33 | } 34 | 35 | list.Sort(new Comparison((Color x, Color y) => 36 | { 37 | var xtotal = x.R + x.G + x.B; 38 | 39 | var ytotal = y.R + y.G + y.B; 40 | 41 | return xtotal.CompareTo(ytotal); // 升序排列 42 | })); 43 | 44 | selectableColors = list; 45 | } 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker/DropDownCustomColorPicker.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {FD2EC7D4-4316-4F8F-8108-8381F0B4B340} 7 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 8 | DropDownCustomColorPicker 9 | DropDownCustomColorPicker 10 | 4 11 | Library 12 | 3.0 13 | false 14 | v4.0 15 | 16 | 17 | 18 | 19 | 3.5 20 | 21 | 22 | 23 | Publish\ 24 | true 25 | Web 26 | true 27 | Foreground 28 | 7 29 | Days 30 | false 31 | false 32 | true 33 | 0 34 | 1.0.0.%2a 35 | false 36 | true 37 | 38 | 39 | true 40 | full 41 | false 42 | .\bin\Debug\ 43 | DEBUG;TRACE 44 | false 45 | 46 | 47 | false 48 | true 49 | .\bin\Release\ 50 | TRACE 51 | false 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 3.0 63 | 64 | 65 | 3.0 66 | 67 | 68 | 3.0 69 | 70 | 71 | 3.0 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Designer 80 | MSBuild:Compile 81 | 82 | 83 | MSBuild:Compile 84 | Designer 85 | 86 | 87 | 88 | 89 | 90 | CustomColorPicker.xaml 91 | 92 | 93 | ColorPicker.xaml 94 | 95 | 96 | 97 | 98 | ResXFileCodeGenerator 99 | Designer 100 | Resources.Designer.cs 101 | 102 | 103 | SettingsSingleFileGenerator 104 | Settings.Designer.cs 105 | 106 | 107 | True 108 | True 109 | Resources.resx 110 | 111 | 112 | True 113 | True 114 | Settings.settings 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | False 124 | .NET Framework 3.5 SP1 125 | true 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | #region Using directives 2 | 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | using System.Resources; 6 | using System.Globalization; 7 | using System.Windows; 8 | using System.Runtime.InteropServices; 9 | 10 | #endregion 11 | 12 | // General Information about an assembly is controlled through the following 13 | // set of attributes. Change these attribute values to modify the information 14 | // associated with an assembly. 15 | [assembly: AssemblyTitle("WindowsApplication1")] 16 | [assembly: AssemblyDescription("")] 17 | [assembly: AssemblyConfiguration("")] 18 | [assembly: AssemblyCompany("")] 19 | [assembly: AssemblyProduct("WindowsApplication1")] 20 | [assembly: AssemblyCopyright("Copyright @ 2006")] 21 | [assembly: AssemblyTrademark("")] 22 | [assembly: AssemblyCulture("")] 23 | [assembly: ComVisible(false)] 24 | 25 | //In order to begin building localizable applications, set 26 | //CultureYouAreCodingWith in your .csproj file 27 | //inside a . For example, if you are using US english 28 | //in your source files, set the to en-US. Then uncomment 29 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 30 | //the line below to match the UICulture setting in the project file. 31 | 32 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 33 | 34 | 35 | [assembly: ThemeInfo( 36 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 37 | //(used if a resource is not found in the page, 38 | // or application resource dictionaries) 39 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 40 | //(used if a resource is not found in the page, 41 | // app, or any theme specific resource dictionaries) 42 | )] 43 | 44 | 45 | // Version information for an assembly consists of the following four values: 46 | // 47 | // Major Version 48 | // Minor Version 49 | // Build Number 50 | // Revision 51 | // 52 | // You can specify all the values or you can default the Revision and Build Numbers 53 | // by using the '*' as shown below: 54 | [assembly: AssemblyVersion("1.0.*")] 55 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DropDownCustomColorPicker.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DropDownCustomColorPicker.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 使用此强类型资源类,为所有资源查找 51 | /// 重写当前线程的 CurrentUICulture 属性。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// 查找 System.Drawing.Bitmap 类型的本地化资源。 65 | /// 66 | internal static System.Drawing.Bitmap ColorSwatchCircle { 67 | get { 68 | object obj = ResourceManager.GetObject("ColorSwatchCircle", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\image.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DropDownCustomColorPicker.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /DropDownCustomColorPicker/Resources/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iqingyu/BlogsDemo/8401c5b8646fcd8700ae2e068e581cecdbec1238/DropDownCustomColorPicker/Resources/image.png -------------------------------------------------------------------------------- /DropDownCustomColorPicker/readme.txt: -------------------------------------------------------------------------------- 1 | 该项目源自: 2 | http://wpfcolorpicker.codeplex.com/ 3 | https://www.codeproject.com/Articles/42849/Making-a-Drop-Down-Style-Custom-Color-Picker-in-WP 4 | 5 | 但是,我已对源码做了大量修改,以适应自己的产品需求,也可以说是完善,也可以说是改进,当然也可能改“烂”了。 6 | 7 | 2017年4月26日 -------------------------------------------------------------------------------- /ParallelDemo/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ParallelDemo/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ParallelDemo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace ParallelDemo 10 | { 11 | /// 12 | /// App.xaml 的交互逻辑 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/AbstractClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Controls; 7 | using ParallelDemo; 8 | using System.Threading; 9 | 10 | namespace ParallelDemo.Demo 11 | { 12 | public abstract class AbstractClass 13 | { 14 | protected static string TXT_NAME = "txtTip"; 15 | protected IView view; 16 | 17 | public AbstractClass(IView view) 18 | { 19 | this.view = view; 20 | } 21 | 22 | protected void PrintInfo(string tip) 23 | { 24 | this.view.DispatcherAction(() => 25 | { 26 | TextBox txtTip = this.view.GetObjectByName(TXT_NAME) as TextBox; 27 | txtTip.PrintInfo(tip); 28 | }); 29 | } 30 | 31 | protected void PrintExInfo(Exception ex) 32 | { 33 | this.view.DispatcherAction(() => 34 | { 35 | TextBox txtTip = this.view.GetObjectByName(TXT_NAME) as TextBox; 36 | txtTip.PrintInfo($"Exception.Message: {ex.Message}"); 37 | }); 38 | } 39 | 40 | public void PrintThreadInfo(string tag, string args) 41 | { 42 | PrintInfo($"Tag:{tag}, Args:{args}, ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}"); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/AtomicityClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace ParallelDemo.Demo 9 | { 10 | public class AtomicityClass : AbstractClass 11 | { 12 | public AtomicityClass(IView view) : base(view) 13 | { 14 | } 15 | 16 | /// 17 | /// 测试原子性 18 | /// 19 | public void TestAtomicity() 20 | { 21 | long test = 0; 22 | 23 | long breakFlag = 0; 24 | int index = 0; 25 | Task.Run(() => 26 | { 27 | base.PrintInfo("开始循环 写数据"); 28 | while (true) 29 | { 30 | test = (index % 2 == 0) ? 0x0 : 0x1234567890abcdef; 31 | 32 | index++; 33 | 34 | if (Interlocked.Read(ref breakFlag) > 0) 35 | { 36 | break; 37 | } 38 | } 39 | 40 | base.PrintInfo("退出循环 写数据"); 41 | }); 42 | 43 | Task.Run(() => 44 | { 45 | base.PrintInfo("开始循环 读数据"); 46 | while (true) 47 | { 48 | long temp = test; 49 | 50 | if (temp != 0 && temp != 0x1234567890abcdef) 51 | { 52 | Interlocked.Increment(ref breakFlag); 53 | base.PrintInfo($"读写撕裂: { Convert.ToString(temp, 16)}"); 54 | break; 55 | } 56 | } 57 | 58 | base.PrintInfo("退出循环 读数据"); 59 | }); 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/AwaitAsyncClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ParallelDemo.Demo 9 | { 10 | public class AwaitAsyncClass : AbstractClass 11 | { 12 | public AwaitAsyncClass(IView view) : base(view) 13 | { 14 | 15 | } 16 | 17 | /// 18 | /// 第一个简单demo 19 | /// 20 | /// 21 | public async Task MethodAsync() 22 | { 23 | PrintInfo($"ManagedThreadId - 1 - :{Thread.CurrentThread.ManagedThreadId}"); 24 | 25 | // 休眠 26 | await Task.Delay(TimeSpan.FromMilliseconds(100)); 27 | 28 | PrintInfo($"ManagedThreadId - 2 - :{Thread.CurrentThread.ManagedThreadId}"); 29 | } 30 | 31 | /// 32 | /// 在循环中使用await, 观察使用的线程数量 33 | /// 34 | /// 35 | public async Task ForMethodAsync() 36 | { 37 | // 休眠 38 | // await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false); 39 | 40 | for (int i = 0; i < 5; i++) 41 | { 42 | await Task.Run(() => 43 | { 44 | // 打印线程id 45 | PrintThreadInfo("ForMethodAsync", i.ToString()); 46 | }); 47 | } 48 | } 49 | 50 | 51 | /// 52 | /// 死锁 Demo 53 | /// 54 | /// 55 | public async Task DeadLockDemoAsync() 56 | { 57 | await Task.Delay(TimeSpan.FromMilliseconds(100));// deadlock 58 | 59 | //await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false);// un-deadlock 60 | 61 | DeadlockDemo.Test(); 62 | } 63 | 64 | } 65 | 66 | /// 67 | /// MSDN Demo 68 | /// 69 | public static class DeadlockDemo 70 | { 71 | private static async Task DelayAsync() 72 | { 73 | await Task.Delay(1000); 74 | } 75 | // This method causes a deadlock when called in a GUI or ASP.NET context. 76 | public static void Test() 77 | { 78 | // Start the delay. 79 | var delayTask = DelayAsync(); 80 | // Wait for the delay to complete. 81 | delayTask.Wait(); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/ConcurrentCollectionClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace ParallelDemo.Demo 10 | { 11 | public class ConcurrentCollectionClass : AbstractClass 12 | { 13 | public ConcurrentCollectionClass(IView view) : base(view) 14 | { 15 | } 16 | 17 | 18 | /// 19 | /// MSDN Demo 20 | /// BlockingCollection.Add() 21 | /// BlockingCollection.CompleteAdding() 22 | /// BlockingCollection.TryTake() 23 | /// BlockingCollection.IsCompleted 24 | /// 25 | public void Demo1() 26 | { 27 | // Construct and fill our BlockingCollection 28 | using (BlockingCollection blocking = new BlockingCollection()) 29 | { 30 | int NUMITEMS = 10000; 31 | 32 | for (int i = 0; i < NUMITEMS; i++) 33 | { 34 | blocking.Add(i); 35 | } 36 | blocking.CompleteAdding(); 37 | 38 | 39 | int outerSum = 0; 40 | 41 | // Delegate for consuming the BlockingCollection and adding up all items 42 | Action action = () => 43 | { 44 | int localItem; 45 | int localSum = 0; 46 | 47 | while (blocking.TryTake(out localItem)) 48 | { 49 | localSum += localItem; 50 | } 51 | Interlocked.Add(ref outerSum, localSum); 52 | }; 53 | 54 | // Launch three parallel actions to consume the BlockingCollection 55 | Parallel.Invoke(action, action, action); 56 | 57 | base.PrintInfo(string.Format("Sum[0..{0}) = {1}, should be {2}", NUMITEMS, outerSum, ((NUMITEMS * (NUMITEMS - 1)) / 2))); 58 | base.PrintInfo(string.Format("bc.IsCompleted = {0} (should be true)", blocking.IsCompleted)); 59 | 60 | } 61 | } 62 | 63 | 64 | /// 65 | /// 限制容量 66 | /// 67 | public void Demo2() 68 | { 69 | BlockingCollection blocking = new BlockingCollection(5); 70 | 71 | Task.Run(() => 72 | { 73 | for (int i = 0; i < 20; i++) 74 | { 75 | blocking.Add(i); 76 | PrintInfo($"add:({i})"); 77 | } 78 | 79 | blocking.CompleteAdding(); 80 | PrintInfo("CompleteAdding"); 81 | }); 82 | 83 | // 等待先生产数据 84 | Task.Delay(500).ContinueWith((t) => 85 | { 86 | while (!blocking.IsCompleted) 87 | { 88 | var n = 0; 89 | if (blocking.TryTake(out n)) 90 | { 91 | PrintInfo($"TryTake:({n})"); 92 | } 93 | } 94 | 95 | PrintInfo("IsCompleted = true"); 96 | }); 97 | 98 | } 99 | 100 | 101 | /// 102 | /// 在 BlockingCollection 中使用Stack 103 | /// 104 | public void Demo3() 105 | { 106 | BlockingCollection blocking = new BlockingCollection(new ConcurrentStack(), 5); 107 | 108 | Task.Run(() => 109 | { 110 | for (int i = 0; i < 20; i++) 111 | { 112 | blocking.Add(i); 113 | PrintInfo($"add:({i})"); 114 | } 115 | 116 | blocking.CompleteAdding(); 117 | PrintInfo("CompleteAdding"); 118 | }); 119 | 120 | // 等待先生产数据 121 | Task.Delay(500).ContinueWith((t) => 122 | { 123 | while (!blocking.IsCompleted) 124 | { 125 | var n = 0; 126 | if (blocking.TryTake(out n)) 127 | { 128 | PrintInfo($"TryTake:({n})"); 129 | } 130 | } 131 | 132 | PrintInfo("IsCompleted = true"); 133 | }); 134 | 135 | 136 | 137 | } 138 | 139 | 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/InterlockedSpinLockClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.Concurrent; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace ParallelDemo.Demo 10 | { 11 | /// 12 | /// 原子操作和自旋锁Demo 13 | /// 14 | public class InterlockedSpinLockClass : AbstractClass 15 | { 16 | public InterlockedSpinLockClass(IView view) : base(view) 17 | { 18 | } 19 | 20 | /// 21 | /// 原子操作-计数 22 | /// 23 | public void Demo1() 24 | { 25 | Task.Run(() => 26 | { 27 | long total = 0; 28 | long result = 0; 29 | 30 | PrintInfo("正在计数"); 31 | 32 | Parallel.For(0, 10, (i) => 33 | { 34 | for (int j = 0; j < 10000000; j++) 35 | { 36 | Interlocked.Increment(ref total); 37 | result++; 38 | } 39 | }); 40 | 41 | PrintInfo($"操作结果应该为\t\t: {10 * 10000000}"); 42 | PrintInfo($"原子操作结果\t\t: {total}"); 43 | PrintInfo($"i++操作结果\t\t: {result}"); 44 | }); 45 | } 46 | 47 | /// 48 | /// 原子操作-单例模式 49 | /// 50 | public void Demo2() 51 | { 52 | ConcurrentQueue queue = new ConcurrentQueue(); 53 | 54 | // 虽然这个测试不严谨、但也或多或少的说明了一些问题 55 | for (int i = 0; i < 10; i++) // 同时分配的线程数过多、调度器反而调度不过来 56 | { 57 | Task.Run(() => 58 | { 59 | var result = InterlockedSingleClass.SingleInstance; 60 | 61 | queue.Enqueue(result); 62 | }); 63 | } 64 | 65 | 66 | // 1秒钟后显示结果 67 | Task.Delay(1000).ContinueWith((t) => 68 | { 69 | PrintInfo($"利用原子操作-单例模式、生成的对象总数:{queue.Count}"); 70 | 71 | InterlockedSingleClass firstItem = null; 72 | queue.TryDequeue(out firstItem); 73 | 74 | for (int i = 0; i < queue.Count;) 75 | { 76 | InterlockedSingleClass temp = null; 77 | queue.TryDequeue(out temp); 78 | 79 | if (temp == null || firstItem == null || !object.ReferenceEquals(temp, firstItem)) 80 | { 81 | PrintInfo("单例模式失效(按照预期、该代码不会被运行到)"); 82 | } 83 | } 84 | 85 | PrintInfo("原子操作-单例模式-运行完毕"); 86 | }); 87 | 88 | } 89 | 90 | 91 | /// 92 | /// 自旋锁Demo,来源MSDN 93 | /// 94 | public void Demo3() 95 | { 96 | SpinLock sl = new SpinLock(); 97 | 98 | StringBuilder sb = new StringBuilder(); 99 | 100 | // Action taken by each parallel job. 101 | // Append to the StringBuilder 10000 times, protecting 102 | // access to sb with a SpinLock. 103 | Action action = () => 104 | { 105 | bool gotLock = false; 106 | for (int i = 0; i < 10000; i++) 107 | { 108 | gotLock = false; 109 | try 110 | { 111 | sl.Enter(ref gotLock); 112 | 113 | sb.Append((i % 10).ToString()); 114 | } 115 | finally 116 | { 117 | // Only give up the lock if you actually acquired it 118 | if (gotLock) 119 | sl.Exit(); 120 | } 121 | } 122 | }; 123 | 124 | // Invoke 3 concurrent instances of the action above 125 | Parallel.Invoke(action, action, action); 126 | 127 | // Check/Show the results 128 | PrintInfo($"sb.Length = {sb.Length} (should be 30000)"); 129 | 130 | PrintInfo($"number of occurrences of '5' in sb: {sb.ToString().Where(c => (c == '5')).Count()} (should be 3000)"); 131 | 132 | } 133 | 134 | 135 | 136 | public class InterlockedSingleClass 137 | { 138 | private static InterlockedSingleClass single = null; 139 | 140 | public static InterlockedSingleClass SingleInstance 141 | { 142 | get 143 | { 144 | // if (single == null) // 为了测试效果,该行代码注释掉 145 | { 146 | Interlocked.CompareExchange(ref single, new InterlockedSingleClass(), null); 147 | } 148 | 149 | return single; 150 | } 151 | } 152 | 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/LockMonitorClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace ParallelDemo.Demo 9 | { 10 | public class LockMonitorClass : AbstractClass 11 | { 12 | public LockMonitorClass(IView view) : base(view) 13 | { 14 | } 15 | 16 | public object thisLock = new object(); 17 | private long index; 18 | 19 | public void AddIndex() 20 | { 21 | lock (this.thisLock) 22 | { 23 | this.index++; 24 | 25 | if (this.index > long.MaxValue / 2) 26 | { 27 | this.index = 0; 28 | } 29 | // 和 index 无关的大量操作 30 | } 31 | } 32 | 33 | public long GetIndex() 34 | { 35 | return this.index; 36 | } 37 | 38 | 39 | 40 | 41 | 42 | public class BankAccount 43 | { 44 | private long id; 45 | private decimal m_balance = 0.0M; 46 | 47 | private object m_balanceLock = new object(); 48 | 49 | public void Deposit(decimal delta) 50 | { 51 | lock (m_balanceLock) 52 | { 53 | m_balance += delta; 54 | } 55 | } 56 | 57 | public void Withdraw(decimal delta) 58 | { 59 | lock (m_balanceLock) 60 | { 61 | if (m_balance < delta) 62 | throw new Exception("Insufficient funds"); 63 | m_balance -= delta; 64 | } 65 | } 66 | 67 | public static void ErrorTransfer(BankAccount a, BankAccount b, decimal delta) 68 | { 69 | a.Withdraw(delta); 70 | b.Deposit(delta); 71 | } 72 | 73 | 74 | public static void Transfer(BankAccount a, BankAccount b, decimal delta) 75 | { 76 | lock (a.m_balanceLock) 77 | { 78 | lock (b.m_balanceLock) 79 | { 80 | a.Withdraw(delta); 81 | b.Deposit(delta); 82 | } 83 | } 84 | } 85 | 86 | public static void RightTransfer(BankAccount a, BankAccount b, decimal delta) 87 | { 88 | if (a.id < b.id) 89 | { 90 | Monitor.Enter(a.m_balanceLock); // A first 91 | Monitor.Enter(b.m_balanceLock); // ...and then B 92 | } 93 | else 94 | { 95 | Monitor.Enter(b.m_balanceLock); // B first 96 | Monitor.Enter(a.m_balanceLock); // ...and then A 97 | } 98 | 99 | try 100 | { 101 | a.Withdraw(delta); 102 | b.Deposit(delta); 103 | } 104 | finally 105 | { 106 | Monitor.Exit(a.m_balanceLock); 107 | Monitor.Exit(b.m_balanceLock); 108 | } 109 | } 110 | 111 | } 112 | 113 | 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/PLinqClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using System.Windows.Controls; 8 | 9 | namespace ParallelDemo.Demo 10 | { 11 | /// 12 | /// Linq 的 并行版本 13 | /// 14 | public class PLinqClass : AbstractClass 15 | { 16 | public PLinqClass(IView view) : base(view) 17 | { 18 | 19 | } 20 | 21 | /// 22 | /// PLinq:Linq的并行版本 23 | /// 24 | public void Demo1() 25 | { 26 | Task.Run(() => 27 | { 28 | var result = Enumerable.Range(1, 10).AsParallel().Where(e => 29 | { 30 | PrintInfo("开始 " + e); 31 | 32 | PrintInfo("休眠 " + e); 33 | Thread.Sleep(1000); 34 | 35 | PrintInfo("结束 " + e); 36 | return e > 5; 37 | }); 38 | 39 | PrintInfo("打印结果"); 40 | 41 | foreach (var item in result) 42 | { 43 | PrintInfo(item.ToString()); 44 | } 45 | 46 | PrintInfo("并行查询执行完毕"); 47 | }); 48 | } 49 | 50 | 51 | /// 52 | /// PLinq:按顺序输出结果 53 | /// 54 | public void Demo2() 55 | { 56 | Task.Run(() => 57 | { 58 | var result = Enumerable.Range(1, 10).AsParallel().AsOrdered().Where(e => 59 | { 60 | PrintInfo("开始 " + e); 61 | 62 | PrintInfo("休眠 " + e); 63 | Thread.Sleep(1000); 64 | 65 | PrintInfo("结束 " + e); 66 | return e > 5; 67 | }); 68 | 69 | PrintInfo("打印结果"); 70 | 71 | foreach (var item in result) 72 | { 73 | PrintInfo(item.ToString()); 74 | } 75 | 76 | PrintInfo("并行查询执行完毕"); 77 | }); 78 | } 79 | 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/ParallelClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Threading; 7 | using System.Windows.Controls; 8 | 9 | namespace ParallelDemo.Demo 10 | { 11 | public class ParallelClass : AbstractClass 12 | { 13 | public ParallelClass(IView view) : base(view) 14 | { 15 | } 16 | 17 | /// 18 | /// Parallel.Invoke并行多个独立的Action 19 | /// 20 | public void Demo1() 21 | { 22 | Task.Run(() => 23 | { 24 | List actions = new List(); 25 | 26 | // 生成并行任务 27 | for (int i = 0; i < 5; i++) 28 | { 29 | // 注意、这里很关键,不可直接使用i变量。 30 | // 原因在稍后的随笔中进行说明 31 | int index = i; 32 | actions.Add(new Action(() => 33 | { 34 | PrintInfo(string.Format("Task{0} 开始", index)); 35 | 36 | PrintInfo(string.Format("Task{0} 休眠1秒", index)); 37 | Thread.Sleep(1000); 38 | 39 | 40 | PrintInfo(string.Format("Task{0} 休眠5秒", index)); 41 | Thread.Sleep(5000); 42 | 43 | PrintInfo(string.Format("Task{0} 结束", index)); 44 | })); 45 | } 46 | 47 | // 执行并行任务 48 | Parallel.Invoke(actions.ToArray()); 49 | 50 | // 当上述的5个任务全部执行完毕后,才会执行该代码 51 | PrintInfo("并行任务执行完毕"); 52 | }); 53 | } 54 | 55 | 56 | /// 57 | /// Parallel简单的For并行 58 | /// 59 | public void Demo2() 60 | { 61 | // 为了实时更新UI、将代码异步执行 62 | Task.Run(() => 63 | { 64 | Parallel.For(1, 100, (index) => 65 | { 66 | PrintInfo(string.Format("Index:{0}, 开始执行Task", index)); 67 | 68 | Thread.Sleep(1000); 69 | PrintInfo(string.Format("Index:{0}, 开始休眠Action 1秒", index)); 70 | 71 | PrintInfo(string.Format("Index:{0}, Task执行完毕", index)); 72 | }); 73 | 74 | PrintInfo("并行任务执行完毕"); 75 | }); 76 | } 77 | 78 | /// 79 | /// 中断Parallel.For并行 80 | /// 81 | public void Demo3() 82 | { 83 | // 为了实时更新UI、将代码异步执行 84 | Task.Run(() => 85 | { 86 | int breakIndex = new Random().Next(10, 50); 87 | PrintInfo(" BreakIndex : -------------------------" + breakIndex); 88 | 89 | Parallel.For(1, 100, (index, state) => 90 | { 91 | PrintInfo(string.Format("Index:{0}, 开始执行Task", index)); 92 | 93 | if (breakIndex == index) 94 | { 95 | PrintInfo(string.Format("Index:{0}, ------------------ Break Task", index)); 96 | state.Break(); 97 | // Break方法执行后、 98 | // 大于 当前索引的并且未被安排执行的迭代将被放弃 99 | // 小于 当前索引的的迭代将继续正常执行直至迭代执行完毕 100 | return; 101 | } 102 | 103 | Thread.Sleep(1000); 104 | PrintInfo(string.Format("Index:{0}, 休眠Action 1秒", index)); 105 | 106 | PrintInfo(string.Format("Index:{0}, Task执行完毕", index)); 107 | }); 108 | 109 | PrintInfo("并行任务执行完毕"); 110 | }); 111 | } 112 | 113 | 114 | /// 115 | /// 终止Parallel.For并行 116 | /// 117 | public void Demo4() 118 | { 119 | // 为了实时更新UI、将代码异步执行 120 | Task.Run(() => 121 | { 122 | int stopIndex = new Random().Next(10, 50); 123 | PrintInfo(" StopIndex : -------------------------" + stopIndex); 124 | 125 | Parallel.For(1, 100, (index, state) => 126 | { 127 | PrintInfo(string.Format("Index:{0}, 开始执行Task", index)); 128 | 129 | if (stopIndex == index) 130 | { 131 | PrintInfo(string.Format("Index:{0}, ------------------ Stop Task", index)); 132 | state.Stop(); 133 | // Stop方法执行后 134 | // 整个迭代将被放弃 135 | return; 136 | } 137 | 138 | Thread.Sleep(1000); 139 | PrintInfo(string.Format("Index:{0}, 休眠Action 1秒", index)); 140 | 141 | PrintInfo(string.Format("Index:{0}, Task执行完毕", index)); 142 | }); 143 | 144 | PrintInfo("并行任务执行完毕"); 145 | }); 146 | } 147 | 148 | 149 | /// 150 | /// Parallel.For并行中的数据聚合 151 | /// 152 | public void Demo5() 153 | { 154 | Task.Run(() => 155 | { 156 | // 求 1 到 10 的阶乘的 和 157 | long total = 0; 158 | Parallel.For(1, 10, 159 | () => 160 | { 161 | PrintInfo("LocalInit"); 162 | return 0; 163 | }, 164 | (index, state, local) => 165 | { 166 | PrintInfo("Body"); 167 | int result = 1; 168 | for (int i = 2; i < index; i++) 169 | { 170 | result *= i; 171 | } 172 | local += result; 173 | return local; 174 | }, 175 | (x) => 176 | { 177 | PrintInfo("LocalFinally"); 178 | Interlocked.Add(ref total, x); 179 | }); 180 | 181 | PrintInfo("Total : " + total); 182 | PrintInfo("并行任务执行完毕"); 183 | }); 184 | 185 | 186 | // MSDN备注: 187 | // 对于参与循环执行的每个线程调用 LocalInit 委托一次,并返回每个线程的初始本地状态。 188 | // 这些初始状态传递到每个线程上的第一个 body 调用。 然后,每个后续正文调用返回可能修改过的状态值,传递到下一个正文调用。 189 | // 最后,每个线程上的最后正文调用返回传递给 LocalFinally 委托的状态值。 190 | // 每个线程调用 localFinally 委托一次,以对每个线程的本地状态执行最终操作。 191 | // 此委托可以被多个线程同步调用;因此您必须同步对任何共享变量的访问。 192 | 193 | // 也就是说: 194 | // 1) 并行中开辟的线程数 决定了 LocalInit、LocalFinally 的调用次数 195 | // 2) 多个 迭代委托、Body 可能被同一个线程调用。 196 | // 3) 迭代委托、Body 中的 local值,并不一定是 LocalInit 的初始值,也有可能是被修改的返回值。 197 | // 4) LocalFinally 可能是被同时调用的,需要注意线程同步问题。 198 | } 199 | 200 | 201 | /// 202 | /// Parallel.ForEach并行 203 | /// 204 | public void Demo6() 205 | { 206 | Task.Run(() => 207 | { 208 | Parallel.ForEach(Enumerable.Range(1, 10), (num) => 209 | { 210 | PrintInfo("Task 开始"); 211 | 212 | 213 | PrintInfo("Task 休眠" + num + "秒"); 214 | Thread.Sleep(TimeSpan.FromSeconds(num)); 215 | 216 | 217 | PrintInfo("Task 结束"); 218 | }); 219 | 220 | PrintInfo("并行任务执行完毕"); 221 | }); 222 | } 223 | 224 | /// 225 | /// Parallel.ForEach中的索引,中断、终止操作 226 | /// 227 | public void Demo7() 228 | { 229 | Task.Run(() => 230 | { 231 | Parallel.ForEach(Enumerable.Range(0, 10), (num, state, index) => 232 | { 233 | // num, 并行数据源中的数据项 234 | // state, 235 | PrintInfo(" Index : " + index + " Num: " + num); 236 | }); 237 | PrintInfo("并行任务执行完毕"); 238 | }); 239 | } 240 | 241 | 242 | 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/TaskClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using System.Windows.Controls; 9 | 10 | namespace ParallelDemo.Demo 11 | { 12 | public class TaskClass : AbstractClass 13 | { 14 | public TaskClass(IView view) : base(view) 15 | { 16 | } 17 | 18 | 19 | /// 20 | /// Task.NET 4.0 中提倡的方式 21 | /// 22 | /// 23 | public void Demo1() 24 | { 25 | // Task 对外公开了构造函数、但是微软并不建议直接使用Task构造函数去实例化对象,而是 使用 Task.Factory.StartNew(); 26 | 27 | // MSDN 中的备注如下: 28 | // For performance reasons, TaskFactory's StartNew method should be the preferred mechanism for creating and scheduling computational tasks, 29 | // but for scenarios where creation and scheduling must be separated, the constructors may be used, 30 | // and the task's Start method may then be used to schedule the task for execution at a later time. 31 | // Task 类还提供了初始化任务但不计划执行任务的构造函数。 出于性能方面的考虑,TaskFactory 的 StartNew 方法应该是创建和计划计算任务的首选机制, 32 | // 但是对于创建和计划必须分开的情况,可以使用构造函数,然后可以使用任务的 Start 方法计划任务在稍后执行。 33 | 34 | 35 | Task.Factory.StartNew(() => 36 | { 37 | base.PrintInfo("Task.Factory.StartNew(一个参数)"); 38 | }).ContinueWith((t) => 39 | { 40 | base.PrintInfo(t.Id.ToString()); 41 | base.PrintInfo(t.CreationOptions.ToString()); 42 | }).ContinueWith((t) => 43 | { 44 | base.PrintInfo(t.Id.ToString()); 45 | base.PrintInfo(t.CreationOptions.ToString()); 46 | }); 47 | 48 | // Task.Factory.StartNew 提供了高达16个的重载函数。 49 | // 其中 Task.Factory.StartNew 是创建带有返回值的异步任务。 50 | 51 | // 以最复杂的重载为例、逐一介绍其参数 52 | // public Task StartNew(Func function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler); 53 | 54 | // function : 回调函数、我想没有必要做解释吧。 55 | // state : 回调函数的传入参数 56 | // CancellationToken : 用以取消Task (后续随笔会做详细介绍) 57 | // TaskCreationOptions : 指定可控制任务的创建和执行的可选行为的标志(后续随笔会做详细介绍) 58 | // TaskScheduler : 一个实例 TaskScheduler 类表示一个任务计划程序. 该值一般都是使用 TaskScheduler.Default 59 | 60 | // 也就是说: 61 | // Task.Factory.StartNew(()=> { }); 62 | // 和 63 | // Task.Factory.StartNew(()=> { }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); 64 | // 两种方式效果是一致的。 65 | 66 | // 如果你想更精细化的控制任务、可以使用其他重载方法、传递不同参数以达到预想的目的。 67 | } 68 | 69 | /// 70 | /// Task初始化任务但并不计划执行 71 | /// 72 | public void Demo2() 73 | { 74 | // 前文说过 Task 提供了构造函数、它提供了初始化任务,但并不去计划执行的方式。 75 | // 让我们再看一下 Task 得构造函数吧,还是以最复杂的为例: 76 | // public Task(Func function, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions); 77 | // 其参数和 Task.Factory.StartNew 相比、 少了TaskScheduler。在性能方面MSDN提示后者会更好。 78 | 79 | base.PrintInfo("初始化任务"); 80 | Task task = new Task(() => 81 | { 82 | base.PrintInfo("被计划的任务开始执行"); 83 | 84 | base.PrintInfo("任务休眠5秒"); 85 | Thread.Sleep(5000); 86 | 87 | base.PrintInfo("任务执行完毕"); 88 | }); 89 | 90 | // 为了保证能实时更新UI、看到代码执行效果、故而将代码异步执行 91 | Task.Factory.StartNew(() => 92 | { 93 | base.PrintInfo("休眠两秒"); 94 | Thread.Sleep(2000); 95 | 96 | base.PrintInfo("将任务列入执行计划"); 97 | task.Start(); 98 | 99 | 100 | base.PrintInfo("等待Task执行完毕"); 101 | task.Wait();// Wait方法 会等待Task执行完毕 102 | base.PrintInfo("Task执行完毕"); 103 | }); 104 | 105 | // 另外再强调一点:Task.Start(), 只是将任务列入执行计划,至于任务什么时候去执行则取决于线程池中什么时候有可用线程。 106 | // Task.Factory.StartNew 也是一样的。 107 | } 108 | 109 | /// 110 | /// Task.NET 4.5 中的简易方式 111 | /// 112 | public void Demo3() 113 | { 114 | Task.Run(() => 115 | { 116 | PrintInfo("简洁的代码"); 117 | }); 118 | 119 | 120 | Task.Run(() => 121 | { 122 | PrintInfo("验证 CreationOptions 属性"); 123 | }).ContinueWith((t) => 124 | { 125 | PrintInfo("CreationOptions:" + t.CreationOptions.ToString()); 126 | }); 127 | } 128 | 129 | 130 | /// 131 | /// 封装APM 132 | /// 133 | public void Demo4() 134 | { 135 | var response = GetResponse("http://www.cnblogs.com/08shiyan"); 136 | 137 | // ... 138 | } 139 | 140 | private Task GetResponse(string url) 141 | { 142 | var request = WebRequest.CreateHttp(url); 143 | request.Method = "GET"; 144 | return Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null); 145 | } 146 | 147 | 148 | /// 149 | /// 封装EAP 150 | /// 151 | public void Demo5() 152 | { 153 | var result = GetResult("http://www.cnblogs.com/08shiyan"); 154 | 155 | // ... 156 | } 157 | 158 | private Task GetResult(string url) 159 | { 160 | TaskCompletionSource source = new TaskCompletionSource(); 161 | 162 | WebClient webClient = new WebClient(); 163 | webClient.DownloadStringCompleted += (sender, args) => 164 | { 165 | if (args.Cancelled) 166 | { 167 | source.SetCanceled(); 168 | return; 169 | } 170 | if (args.Error != null) 171 | { 172 | source.SetException(args.Error); 173 | return; 174 | } 175 | source.SetResult(args.Result); 176 | }; 177 | webClient.DownloadStringAsync(new Uri(url), null); 178 | 179 | return source.Task; 180 | } 181 | 182 | 183 | 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/ThreadPoolClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using System.Windows.Controls; 8 | 9 | namespace ParallelDemo.Demo 10 | { 11 | /// 12 | /// ThreadPool Demo 13 | /// 注: ThreadPool 为静态类,其提供的方法都为静态方法。 14 | /// 15 | public class ThreadPoolClass : AbstractClass 16 | { 17 | private AutoResetEvent waitObject; 18 | 19 | 20 | public ThreadPoolClass(IView view) : base(view) 21 | { 22 | this.waitObject = new AutoResetEvent(false); 23 | } 24 | 25 | /// 26 | /// ThreadPool 的第一种应用场景 27 | /// 将需要异步执行的方法、排入队列,当有可用线程时执行被排入队列的方法 28 | /// 29 | public void Demo1() 30 | { 31 | // 该应用场景下 ThreadPool 提供如下两种形式的重载方法 32 | // public static bool QueueUserWorkItem(WaitCallback callBack); 33 | // public static bool QueueUserWorkItem(WaitCallback callBack, object state); 34 | 35 | // WaitCallback 为 delegate, 一个object类型的入参,没有返回值。 36 | // public delegate void WaitCallback(object state); 37 | 38 | 39 | base.PrintInfo(nameof(ThreadPool.QueueUserWorkItem)); 40 | 41 | ThreadPool.QueueUserWorkItem((state) => 42 | { 43 | this.PrintInfo("等待一秒"); 44 | Thread.Sleep(1000); 45 | this.PrintInfo("任务执行完毕"); 46 | }); 47 | } 48 | 49 | /// 50 | /// ThreadPool 的第二种应用场景 51 | /// 注册等待信号对象(WaitHandle)、并在其收到信号时触发回调函数 52 | /// 53 | public void Demo2() 54 | { 55 | // 该应用场景下 ThreadPool 提供了四种形式的重载方法, 下面的重载形式在我看来是最具有直观意义的 56 | // public static RegisteredWaitHandle RegisterWaitForSingleObject( 57 | // WaitHandle waitObject, WaitOrTimerCallback callBack, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce); 58 | 59 | // 其中 WaitHandle 为需要等待信号的类型 的 抽象基类,在后续随笔中会做详细介绍,在此不再多言。 60 | 61 | // 其中 WaitOrTimerCallback 为 回调函数委托 62 | // public delegate void WaitOrTimerCallback(object state, bool timedOut); 63 | 64 | // state 参数为 回调函数的传入参数 65 | 66 | // millisecondsTimeOutInterval 参数为 计时器超时周期, -1 为永不超时、即一直等待。 67 | // 对于此参数、第一次接触到的人可能有疑问、怎么还有周期? 68 | // 因为 信号可以重复接到多次、所以当每次接到信号后、或者超时后计时器都会重新计时, 所以有了周期的含义。 69 | 70 | // executeOnlyOnce, True 表示只执行一次, False 会一直等到该信号对象被取消注册,否则 只要接到信号或者超时就会触发回调函数。 71 | 72 | base.PrintInfo(nameof(ThreadPool.RegisterWaitForSingleObject)); 73 | 74 | ThreadPool.RegisterWaitForSingleObject(this.waitObject, (state, timeout) => 75 | { 76 | this.PrintInfo("++++++等待对象收到信号++++++"); 77 | 78 | }, null, -1, false); 79 | 80 | 81 | ThreadPool.QueueUserWorkItem((state) => 82 | { 83 | this.PrintInfo("等待一秒"); 84 | Thread.Sleep(1000); 85 | 86 | this.PrintInfo("等待对象发出信号"); 87 | this.waitObject.Set(); 88 | 89 | this.PrintInfo("等待5秒"); 90 | Thread.Sleep(5000); 91 | 92 | this.PrintInfo("等待对象发出信号"); 93 | this.waitObject.Set(); 94 | 95 | }); 96 | 97 | } 98 | 99 | 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /ParallelDemo/Demo/VariableCapturingClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ParallelDemo.Demo 8 | { 9 | /// 10 | /// 闭包、变量捕获相关Demo 11 | /// 12 | public class VariableCapturingClass : AbstractClass 13 | { 14 | public VariableCapturingClass(IView view) : base(view) 15 | { 16 | 17 | } 18 | 19 | /// 20 | /// 闭包、变量捕获引发的bug 21 | /// 22 | public void Demo1() 23 | { 24 | int total = 0; 25 | 26 | List taskList = new List(); 27 | 28 | for (int i = 0; i < 10; i++) 29 | { 30 | var task = Task.Run(() => 31 | { 32 | System.Threading.Interlocked.Add(ref total, i); 33 | }); 34 | 35 | taskList.Add(task); 36 | } 37 | 38 | Task.WaitAll(taskList.ToArray()); 39 | 40 | PrintInfo(total.ToString()); 41 | 42 | if (total > 49) 43 | { 44 | PrintInfo("闭包、捕获了变量i,使结果超出预期"); 45 | } 46 | } 47 | 48 | /// 49 | /// 窥探闭包的本质 50 | /// 51 | public void Demo2() 52 | { 53 | var func = GetFunc(); 54 | 55 | PrintInfo($"result:{func().ToString()}"); // 输出结果 结果为12 56 | } 57 | 58 | private Func GetFunc() 59 | { 60 | int result = 10; 61 | 62 | Func func = () => 63 | { 64 | result++; 65 | 66 | return result; 67 | }; 68 | 69 | result++; 70 | 71 | return func; 72 | } 73 | 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ParallelDemo/IView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Controls; 7 | 8 | namespace ParallelDemo 9 | { 10 | public interface IView 11 | { 12 | Control Control { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ParallelDemo/IViewExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Controls; 7 | using System.Windows.Threading; 8 | 9 | namespace ParallelDemo 10 | { 11 | public static class IViewExtension 12 | { 13 | public static Dispatcher GetDispatcher(this IView view) 14 | { 15 | return view.Control.Dispatcher; 16 | } 17 | 18 | public static void DispatcherAction(this IView view, Action action) 19 | { 20 | view.Control.Dispatcher.Invoke(action); 21 | } 22 | 23 | public static object GetObjectByName(this IView view, string name) 24 | { 25 | return view.Control.FindName(name); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ParallelDemo/ParallelDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6D3C0CF4-4029-4E7A-A33E-B0D038B3BF92} 8 | WinExe 9 | Properties 10 | ParallelDemo 11 | ParallelDemo 12 | v4.5 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 4.0 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | MSBuild:Compile 56 | Designer 57 | 58 | 59 | MSBuild:Compile 60 | Designer 61 | 62 | 63 | App.xaml 64 | Code 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Window1.xaml 82 | Code 83 | 84 | 85 | 86 | 87 | Code 88 | 89 | 90 | True 91 | True 92 | Resources.resx 93 | 94 | 95 | True 96 | Settings.settings 97 | True 98 | 99 | 100 | ResXFileCodeGenerator 101 | Resources.Designer.cs 102 | 103 | 104 | SettingsSingleFileGenerator 105 | Settings.Designer.cs 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 120 | -------------------------------------------------------------------------------- /ParallelDemo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // 有关程序集的一般信息由以下 8 | // 控制。更改这些特性值可修改 9 | // 与程序集关联的信息。 10 | [assembly: AssemblyTitle("ParallelDemo")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("ParallelDemo")] 15 | [assembly: AssemblyCopyright("Copyright © 2016")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | //将 ComVisible 设置为 false 将使此程序集中的类型 20 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 21 | //请将此类型的 ComVisible 特性设置为 true。 22 | [assembly: ComVisible(false)] 23 | 24 | //若要开始生成可本地化的应用程序,请 25 | // 中的 .csproj 文件中 26 | //例如,如果您在源文件中使用的是美国英语, 27 | //使用的是美国英语,请将 设置为 en-US。 然后取消 28 | //对以下 NeutralResourceLanguage 特性的注释。 更新 29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置 36 | //(当资源未在页面 37 | //或应用程序资源字典中找到时使用) 38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 39 | //(当资源未在页面 40 | //、应用程序或任何主题专用资源字典中找到时使用) 41 | )] 42 | 43 | 44 | // 程序集的版本信息由下列四个值组成: 45 | // 46 | // 主版本 47 | // 次版本 48 | // 生成号 49 | // 修订号 50 | // 51 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 52 | // 方法是按如下所示使用“*”: : 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /ParallelDemo/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本: 4.0.30319.42000 5 | // 6 | // 对此文件的更改可能导致不正确的行为,如果 7 | // 重新生成代码,则所做更改将丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ParallelDemo.Properties 12 | { 13 | 14 | 15 | /// 16 | /// 强类型资源类,用于查找本地化字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// 返回此类使用的缓存 ResourceManager 实例。 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ParallelDemo.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// 覆盖当前线程的 CurrentUICulture 属性 56 | /// 使用此强类型的资源类的资源查找。 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ParallelDemo/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /ParallelDemo/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ParallelDemo.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ParallelDemo/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ParallelDemo/Window1.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /PluginDemo.NewDomain/NonMarshalByRefObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace PluginDemo.NewDomain 7 | { 8 | /// 9 | /// 未继承 MarshalByRefObject, 不可以跨AppDomain交换消息 10 | /// 11 | public class NonMarshalByRefObject 12 | { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /PluginDemo.NewDomain/NonMarshalByRefObjectAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace PluginDemo.NewDomain 7 | { 8 | [Serializable] 9 | public class NonMarshalByRefObjectAction // : MarshalByRefObject 10 | { 11 | private int index = 0; 12 | 13 | public void Add() 14 | { 15 | this.index++; 16 | } 17 | 18 | public void TestAction() 19 | { 20 | this.index++; 21 | 22 | StringBuilder sb = new StringBuilder(); 23 | 24 | sb.AppendLine($"current index is {index} "); 25 | 26 | sb.AppendLine($"如果一个类型 【不是】 {nameof(MarshalByRefObject)}的子类 并且 【没有标记】 {nameof(SerializableAttribute)}, "); 27 | sb.AppendLine($"则该类型的对象不能被其他AppDomain中的对象所访问, 当然这种情况下的该类型对象中的成员也不可能被访问到了 "); 28 | sb.AppendLine("反之,则可以被其他AppDomain中的对象所访问 "); 29 | 30 | sb.AppendLine(); 31 | sb.AppendLine($"如果一个类型 【是】 {nameof(MarshalByRefObject)}的子类, 则跨AppDomain所得到的是 【对象的引用】(为了好理解说成对象引用,实质为代理)"); 32 | 33 | sb.AppendLine(); 34 | sb.AppendLine($"如果一个类型 【标记】 {nameof(SerializableAttribute)}, 则跨AppDomain所得到的是 【对象的副本】,该副本是通过序列化进行值封送的 "); 35 | sb.AppendLine("此时传递到其他AppDomain 中的对象 和 当前对象已经不是同一个对象了(只传递了副本),这一点 通过 index 字段值 可以得到印证 "); 36 | sb.AppendLine("MSDN 参考文档"); 37 | sb.AppendLine("https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=ZH-CN&k=k(System.MarshalByRefObject);k(SolutionItemsProject);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.0);k(DevLang-csharp)&rd=true#备注"); 38 | 39 | 40 | sb.AppendLine(); 41 | sb.AppendLine($"如果一个类型 【是】 {nameof(MarshalByRefObject)}的子类 并且 【标记了】 {nameof(SerializableAttribute)}, "); 42 | sb.AppendLine($"则 {nameof(MarshalByRefObject)} 的优先级更高 "); 43 | 44 | sb.AppendLine(); 45 | 46 | sb.AppendLine("另外:.net 基本类型 、string 类型、 List 等类型,虽然没有标记 SerializableAttribute, 但是他们依然可以序列化。也就是说这些类型都可以在不同的AppDomain之间通信,只是传递的都是对象副本。"); 47 | 48 | sb.AppendLine(); 49 | 50 | var result = this.GetType().IsSubclassOf(typeof(MarshalByRefObject)); 51 | sb.AppendLine($"该类型是否是 {nameof(MarshalByRefObject)} 的子类: {result.ToString()}"); 52 | 53 | var arr = this.GetType().GetCustomAttributes(typeof(SerializableAttribute), false); 54 | sb.AppendLine($"该类型是否是 标记了 {nameof(SerializableAttribute)} : {(arr != null && arr.Length > 0 ? true : false).ToString()}"); 55 | 56 | 57 | throw new Exception(sb.ToString()); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /PluginDemo.NewDomain/Plugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using PluginDemo; 6 | 7 | namespace PluginDemo.NewDomain 8 | { 9 | 10 | /// 11 | /// 支持跨应用程序域访问 12 | /// 13 | public class Plugin : MarshalByRefObject, IPlugin 14 | { 15 | // AppDomain被卸载后,静态成员的内存会被释放掉 16 | private static int length; 17 | 18 | /// 19 | /// int 作为基础数据类型, 是持续序列化的. 20 | /// 在与其他AppDomain通讯时,传递的是对象副本(通过序列化进行的值封送) 21 | /// 22 | /// 23 | public int GetInt() 24 | { 25 | length += new Random().Next(10000); 26 | 27 | return length; 28 | } 29 | 30 | 31 | /// 32 | /// string 作为特殊的class, 也是持续序列化的. 33 | /// 在与其他AppDomain通讯时,传递的是对象副本(通过序列化进行的值封送) 34 | /// 35 | /// 36 | public string GetString() 37 | { 38 | return "iqingyu"; 39 | } 40 | 41 | 42 | 43 | /// 44 | /// 未继承 MarshalByRefObject 并且 不支持序列化 的 class, 是不可以跨AppDomain通信的,也就是说其他AppDomain是获取不到其对象的 45 | /// 46 | /// 47 | public object GetNonMarshalByRefObject() 48 | { 49 | return new NonMarshalByRefObject(); 50 | } 51 | 52 | private NonMarshalByRefObjectAction obj = new NonMarshalByRefObjectAction(); 53 | 54 | /// 55 | /// 委托,和 委托所指向的类型相关 56 | /// 也就是说,如果其指向的类型支持跨AppDomain通信,那个其他AppDomain就可以获取都该委托, 反之,则不能获取到 57 | /// 58 | /// 59 | public Action GetAction() 60 | { 61 | obj.Add(); 62 | obj.Add(); 63 | //obj.Add(); 64 | 65 | return obj.TestAction; 66 | } 67 | 68 | private List list = new List() { "A", "B" }; 69 | 70 | /// 71 | /// List 也是持续序列化的, 当然前提是T也必须支持跨AppDomain通信 72 | /// 在与其他AppDomain通讯时,传递的是对象副本(通过序列化进行的值封送) 73 | /// 74 | /// 75 | public List GetList() 76 | { 77 | return this.list; 78 | // return new List() { this.GetAction() }; 79 | } 80 | 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /PluginDemo.NewDomain/PluginDemo.NewDomain.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {60D4EE42-C507-41B3-ADF5-432AD02A6FED} 8 | Library 9 | Properties 10 | PluginDemo.NewDomain 11 | PluginDemo.NewDomain 12 | v4.0 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | {803e039b-bf06-4d35-966f-0bc4a96d4a98} 52 | PluginDemo 53 | 54 | 55 | 56 | 57 | copy $(TargetPath) $(SolutionDir)PluginDemo\$(OutDir) 58 | 59 | 66 | -------------------------------------------------------------------------------- /PluginDemo.NewDomain/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("PluginDemo.NewDomain")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PluginDemo.NewDomain")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | //将 ComVisible 设置为 false 将使此程序集中的类型 18 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("60d4ee42-c507-41b3-adf5-432ad02a6fed")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 33 | // 方法是按如下所示使用“*”: : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PluginDemo/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /PluginDemo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Windows; 7 | 8 | namespace PluginDemo 9 | { 10 | /// 11 | /// App.xaml 的交互逻辑 12 | /// 13 | public partial class App : Application 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /PluginDemo/IPlugin.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Input; 6 | 7 | namespace PluginDemo 8 | { 9 | public interface IPlugin 10 | { 11 | int GetInt(); 12 | 13 | string GetString(); 14 | 15 | object GetNonMarshalByRefObject(); 16 | 17 | Action GetAction(); 18 | 19 | List GetList(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PluginDemo/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /PluginDemo/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Diagnostics; 4 | using System.Runtime.Serialization.Formatters.Binary; 5 | 6 | namespace PluginDemo 7 | { 8 | /// 9 | /// MainWindow.xaml 的交互逻辑 10 | /// 11 | public partial class MainWindow : Window 12 | { 13 | private AppDomain domain; 14 | private IPlugin remoteIPlugin; 15 | 16 | 17 | 18 | public MainWindow() 19 | { 20 | InitializeComponent(); 21 | } 22 | 23 | private void loadBtn_Click(object sender, RoutedEventArgs e) 24 | { 25 | try 26 | { 27 | unLoadBtn_Click(sender, e); 28 | 29 | this.txtBlock.Text = string.Empty; 30 | 31 | // 在新的AppDomain中加载 RemoteCamera 类型 32 | AppDomainSetup objSetup = new AppDomainSetup(); 33 | objSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory; 34 | objSetup.ShadowCopyFiles = "true"; 35 | 36 | // 虽然此方法已经被标记为过时方法, msdn备注也提倡不使用该方法, 37 | // 但是 以.net 4.0 + win10环境测试,还必须调用该方法 否则,即便卸载了应用程序域 dll 还是未被解除锁定 38 | AppDomain.CurrentDomain.SetShadowCopyFiles(); 39 | 40 | this.domain = AppDomain.CreateDomain("RemoteAppDomain", null, objSetup); 41 | this.remoteIPlugin = this.domain.CreateInstance("PluginDemo.NewDomain", "PluginDemo.NewDomain.Plugin").Unwrap() as IPlugin; 42 | 43 | this.txtBlock.AppendText("创建AppDomain成功\r\n\r\n"); 44 | } 45 | catch (Exception ex) 46 | { 47 | this.txtBlock.AppendText(ex.Message); 48 | this.txtBlock.AppendText("\r\n\r\n"); 49 | } 50 | } 51 | 52 | private void unLoadBtn_Click(object sender, RoutedEventArgs e) 53 | { 54 | if (this.remoteIPlugin != null) 55 | { 56 | this.remoteIPlugin = null; 57 | } 58 | 59 | if (this.domain != null) 60 | { 61 | AppDomain.Unload(this.domain); 62 | this.domain = null; 63 | this.txtBlock.AppendText("卸载AppDomain成功\r\n\r\n"); 64 | } 65 | } 66 | 67 | 68 | 69 | private void invokeBtn_Click(object sender, RoutedEventArgs e) 70 | { 71 | if (this.remoteIPlugin == null) 72 | return; 73 | 74 | this.txtBlock.AppendText($"GetInt():{ this.remoteIPlugin.GetInt().ToString()}\r\n"); 75 | this.txtBlock.AppendText($"GetString():{ this.remoteIPlugin.GetString().ToString()}\r\n"); 76 | 77 | 78 | try 79 | { 80 | this.remoteIPlugin.GetNonMarshalByRefObject(); 81 | } 82 | catch (Exception ex) 83 | { 84 | this.txtBlock.AppendText($"GetNonMarshalByRefObject():{ ex.Message}\r\n"); 85 | if (Debugger.IsAttached) 86 | { 87 | Debugger.Break(); 88 | } 89 | } 90 | 91 | this.txtBlock.AppendText("\r\n\r\n\r\n"); 92 | 93 | Action firstAction = null; 94 | 95 | try 96 | { 97 | firstAction = this.remoteIPlugin.GetAction(); 98 | 99 | firstAction(); 100 | } 101 | catch (Exception ex) 102 | { 103 | this.txtBlock.AppendText($"GetAction(), firstAction: { ex.Message}\r\n"); 104 | if (Debugger.IsAttached) 105 | { 106 | Debugger.Break(); 107 | } 108 | } 109 | 110 | try 111 | { 112 | this.txtBlock.AppendText("\r\n\r\n\r\n"); 113 | var secondAction = this.remoteIPlugin.GetAction(); 114 | 115 | secondAction(); 116 | } 117 | catch (Exception ex) 118 | { 119 | this.txtBlock.AppendText($"GetAction(), secondAction: { ex.Message}\r\n"); 120 | if (Debugger.IsAttached) 121 | { 122 | Debugger.Break(); 123 | } 124 | } 125 | 126 | 127 | try 128 | { 129 | this.txtBlock.AppendText("\r\n\r\n\r\n"); 130 | if (firstAction != null) 131 | firstAction(); 132 | } 133 | catch (Exception ex) 134 | { 135 | this.txtBlock.AppendText($"firstAction: { ex.Message}\r\n"); 136 | if (Debugger.IsAttached) 137 | { 138 | Debugger.Break(); 139 | } 140 | } 141 | 142 | this.txtBlock.AppendText("\r\n\r\n\r\n"); 143 | 144 | try 145 | { 146 | var list1 = this.remoteIPlugin.GetList(); 147 | this.txtBlock.AppendText($"list1.Count: {list1.Count}\r\n"); 148 | var list2 = this.remoteIPlugin.GetList(); 149 | this.txtBlock.AppendText($"list2.Count: {list2.Count}\r\n"); 150 | 151 | 152 | this.txtBlock.AppendText("\r\n"); 153 | list1.Add("C"); 154 | this.txtBlock.AppendText("list1.Add(\"C\")\r\n"); 155 | 156 | 157 | this.txtBlock.AppendText($"list1.Count: {list1.Count}\r\n"); 158 | this.txtBlock.AppendText($"list2.Count: {list2.Count}\r\n"); 159 | 160 | this.txtBlock.AppendText("!!!此例子,也间接证明支持序列化的类型,在跨AppDomain通信时,传递的是对象副本\r\n\r\n"); 161 | } 162 | catch (Exception ex) 163 | { 164 | this.txtBlock.AppendText($"GetList(): { ex.Message}\r\n"); 165 | if (Debugger.IsAttached) 166 | { 167 | Debugger.Break(); 168 | } 169 | } 170 | 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /PluginDemo/PluginDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {803E039B-BF06-4D35-966F-0BC4A96D4A98} 8 | WinExe 9 | Properties 10 | PluginDemo 11 | PluginDemo 12 | v4.0 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 4.0 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | MSBuild:Compile 55 | Designer 56 | 57 | 58 | MSBuild:Compile 59 | Designer 60 | 61 | 62 | App.xaml 63 | Code 64 | 65 | 66 | 67 | MainWindow.xaml 68 | Code 69 | 70 | 71 | 72 | 73 | Code 74 | 75 | 76 | True 77 | True 78 | Resources.resx 79 | 80 | 81 | True 82 | Settings.settings 83 | True 84 | 85 | 86 | ResXFileCodeGenerator 87 | Resources.Designer.cs 88 | 89 | 90 | SettingsSingleFileGenerator 91 | Settings.Designer.cs 92 | 93 | 94 | 95 | 96 | 103 | -------------------------------------------------------------------------------- /PluginDemo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // 有关程序集的一般信息由以下 8 | // 控制。更改这些特性值可修改 9 | // 与程序集关联的信息。 10 | [assembly: AssemblyTitle("PluginDemo")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("PluginDemo")] 15 | [assembly: AssemblyCopyright("Copyright © 2017")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | //将 ComVisible 设置为 false 将使此程序集中的类型 20 | //对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, 21 | //请将此类型的 ComVisible 特性设置为 true。 22 | [assembly: ComVisible(false)] 23 | 24 | //若要开始生成可本地化的应用程序,请 25 | // 中的 .csproj 文件中 26 | //例如,如果您在源文件中使用的是美国英语, 27 | //使用的是美国英语,请将 设置为 en-US。 然后取消 28 | //对以下 NeutralResourceLanguage 特性的注释。 更新 29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置 36 | //(当资源未在页面 37 | //或应用程序资源字典中找到时使用) 38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置 39 | //(当资源未在页面 40 | //、应用程序或任何主题专用资源字典中找到时使用) 41 | )] 42 | 43 | 44 | // 程序集的版本信息由下列四个值组成: 45 | // 46 | // 主版本 47 | // 次版本 48 | // 生成号 49 | // 修订号 50 | // 51 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, 52 | // 方法是按如下所示使用“*”: : 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /PluginDemo/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本: 4.0.30319.42000 5 | // 6 | // 对此文件的更改可能导致不正确的行为,如果 7 | // 重新生成代码,则所做更改将丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace PluginDemo.Properties 12 | { 13 | 14 | 15 | /// 16 | /// 强类型资源类,用于查找本地化字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// 返回此类使用的缓存 ResourceManager 实例。 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PluginDemo.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// 覆盖当前线程的 CurrentUICulture 属性 56 | /// 使用此强类型的资源类的资源查找。 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /PluginDemo/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /PluginDemo/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace PluginDemo.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /PluginDemo/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iqingyu/BlogsDemo/8401c5b8646fcd8700ae2e068e581cecdbec1238/readme.txt --------------------------------------------------------------------------------