控制反转:我们向IOC容器发出获取一个对象实例的一个请求,IOC容器便把这个对象实例“注入”到我们的手中,在这个过程中你不是一个控制者而是一个请求者,依赖于容器提供给你的资源,控制权落到了容器身上。这个过程就是控制反转。 依赖注入:我们向容器发出请求以后,获得这个对象实例的过程就叫依赖注入。 IoC模式其实是工厂设计模式的升华,在微软较早的PetShop项目通过反射技术做了很多工厂。我认为可能是IoC的原型。 关于Ioc的框架有很多,比如Castle Windsor、Unity、Spring.NET、StructureMap,我们这边使用微软提供的Unity做示例,你可以使用 Nuget 添加 Unity ,也可以引用Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll,下面我们就一步一步的学习下 Unity依赖注入 的详细使用。 Unity是微软推出的IOC框架, 使用这个框架,可以实现AOP面向切面编程,便于代码的后期维护,此外,这套框架还自带单例模式,可以提高程序的运行效率。 下面是我自己的案例,以供日后参考: 使用VS2015的Nuget管理器下载Unity。 程序员接口类:
1 2 3 4 5 6 7 |
namespace UnityDemo { public interface IProgrammer { void Working(); } } |
程序员类:
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 |
using System; namespace UnityDemo { public class CSharp : IProgrammer { public void Working() { Console.WriteLine("programming C# ..."); } } public class VB : IProgrammer { public void Working() { Console.WriteLine("programming VB ..."); } } public class Java : IProgrammer { public void Working() { Console.WriteLine("programming Java ..."); } } } |
App.config配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?xml version="1.0" encoding="utf-8"?> <configuration> <!--<startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/> </startup>--> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/> </configSections> <unity> <containers> <container name="Programmer"> <register type="UnityDemo.IProgrammer,UnityDemo" mapTo="UnityDemo.CSharp,UnityDemo" name="CSharp"></register> <register type="UnityDemo.IProgrammer,UnityDemo" mapTo="UnityDemo.VB,UnityDemo" name="VB"></register> <register type="UnityDemo.IProgrammer,UnityDemo" mapTo="UnityDemo.Java,UnityDemo" name="Java"></register> </container> </containers> </unity> </configuration> |
主程序代码:
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 |
using Microsoft.Practices.Unity; using Microsoft.Practices.Unity.Configuration; using System; using System.Configuration; namespace UnityDemo { class Program { private static IUnityContainer container = null; static void Main(string[] args) { RegisterContainer(); var programmer = container.Resolve<IProgrammer>("CSharp"); //var programmer = container.Resolve<IProgrammer>("VB"); programmer.Working(); Console.ReadKey(); } private static void RegisterContainer() { container = new UnityContainer(); UnityConfigurationSection config =(UnityConfigurationSection) ConfigurationManager.GetSection(UnityConfigurationSection.SectionName); config.Configure(container, "Programmer"); } } } |
运行结果: 这个Demo的思想: 定义一个程序员接口IProgrammer,有3个实现这个接口的程序员类,分别是CSharp、VB、Java, 然后配置App.config文件,里面首先定义一个配置节点(configSection),名称为Unity,引用的命名空间是微软的Unity, 接着下面定义一个unity节点,里面的容器集合(containers),集合里面可以有多个容器,这个Demo里的只有一个容器,里面包含了3个注册节点(register),分别是CSharp,VB、Java,注意,里节点中的name属性用于在程序调用时选择类的。 在主程序的代码中, 1、有一个Unity的容器container; 2、注册容器的方法RegisterContainer,作用是到App.config中读取容器的信息,把接口和3个类的映射关系注册到容器中; 3、主程序运行前,先注册容器,然后通过容器的Resolve方法,实例化一个programmer类,原理大概是,我们把类名传入到容器中,容器会根据类名,找到App.config中对应的register映射关系,容器就会通过反射得到相应的程序员类,返回这个类。 4、此时programmer类就实例化完成,可以使用了。 使用了Unity,以后如果需要追加新的类,只需要实现IProgrammer接口,在配置文件追加映射关系,执行代码中修改name的值就能使用新的类了。 这样,我们不需要删除旧的代码,就能追加新的功能,便于维护代码。 本人的Demo下载 转自: https://www.cnblogs.com/chenyucong/p/6272600.html
View Details官网生成的ABP + module zero出现Default language is not defined!的错误,原因是数据库没有language数据,而不是缺少language.xml资源文件,所以先创建数据库就好了。 解决方法: 1.选择Web项目作为起始项目。 2.打开程序包管理控制台,选择“EntityFramework”项目作为默认项目,然后运行EF的’Update-Database’命令。该命令会创建数据库。 3.运行该应用,默认的用户名是’admin’,密码是’123qwe’。 在执行第2步时遇到了如下错误: Update-Database : 无法将“Update-Database”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后重试。 原因可能是EntityFramework没有安装,Install-Package EntityFramework就好了。什么?还是不行?全部重新生成再重新打开vs试试吧! https://blog.csdn.net/klo220/article/details/51138582
View Details摘要 我相信很多人对这个再熟悉不过了。对已经修改的集合进行操作就会出现这个错。 解决办法 比如有下面的一段代码,我们创建一个集合,并向集合中添加10个数,然后,我们循环再将这些数移除了。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
static void Main(string[] args) { List<int> lst = new List<int>(); for (int i = 0; i < 10; i++) { lst.Add(i); } foreach (var item in lst) { lst.Remove(item); } Console.Read(); } |
出现了….. 是不是被泛型集合提供的方法坑了?我记得很久之前我也被坑过。很疑惑吧,其实也很简单,因为你如果移除了一项,集合的元素个数是变化的。这个时候元素会重排,第二个元素的索引由1变为0,后面的依次往前移动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
static void Main(string[] args) { List<int> lst = new List<int>(); for (int i = 0; i < 10; i++) { lst.Add(i); } var result = lst; Console.WriteLine("lst的count" + lst.Count); lst.Remove(0); Console.WriteLine("lst的count" + lst.Count); for (int i = 0; i < lst.Count; i++) { Console.WriteLine("索引:{0},值:{1}", i, lst[i]); } Console.Read(); } |
上面的代码为集合添加10个元素。然后输出当前集合的count,接着将索引为0的元素移除。这个时候集合中应该没有元素0了。然后输出集合的元素个数。输出此时的集合中索引和对应的值。如图所示 可以看到,本来索引为1的1,往前移动了,此时他的索引变为了0.所以在使用foreach移除的时候,集合是变化的,是不允许的。难道就没办法操作了吗?当然有,它不是移除一个集合就少一个吗》 此时,我们可以通过for循环,从集合的队尾移除,这个时候移除队尾的元素,虽然集合的count变了,但他们的索引没有变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
static void Main(string[] args) { List<int> lst = new List<int>(); for (int i = 0; i < 10; i++) { lst.Add(i); } var result = lst; Console.WriteLine("lst的count" + lst.Count); lst.Remove(0); Console.WriteLine("lst的count" + lst.Count); for (int i = lst.Count - 1; i >= 0; i--) { Console.WriteLine("索引:{0},值:{1}", i, lst[i]); Console.WriteLine("移除了元素:{0}", lst[i]); lst.RemoveAt(i); } Console.Read(); } |
那么我们只移除满足条件的是否也可以通过for循环呢?当然可以,foreach你不是不让吗?又不是只有你一个可以循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
static void Main(string[] args) { List<int> lst = new List<int>(); for (int i = 0; i < 10; i++) { lst.Add(i); } var result = lst; Console.WriteLine("lst的count" + lst.Count); lst.Remove(0); Console.WriteLine("lst的count" + lst.Count); for (int i = 0; i < lst.Count; i++) { Console.WriteLine("索引:{0},值:{1}", i, lst[i]); if (lst[i] % 2 == 0) { Console.WriteLine("移除了元素:{0}", lst[i]); lst.RemoveAt(i); } } Console.Read(); } |
总结 前不久刚有人遇到,这里还是记录一下吧。 from:https://www.cnblogs.com/wolf-sun/p/5721457.html
View Details在常用的三层架构中,通常都是通过数据访问层来修改或者查询数据,一般修改和查询使用的是相同的实体。在一些业务逻辑简单的系统中可能没有什么问题,但是随着系统逻辑变得复杂,用户增多,这种设计就会出现一些性能问题。虽然在DB上可以做一些读写分离的设计,但在业务上如果在读写方面混合在一起的话,仍然会出现一些问题。 本文介绍了命令查询职责分离模式(Command Query Responsibility Segregation,CQRS),该模式从业务上分离修改 (Command,增,删,改,会对系统状态进行修改)和查询(Query,查,不会对系统状态进行修改)的行为。从而使得逻辑更加清晰,便于对不同部分进行针对性的优化。文章首先简要介绍了传统的CRUD方式存在的问题,接着介绍了CQRS模式,最后以一个简单的在线日记系统演示了如何实现CQRS模式。要谈到读写操作,首先我们来看传统的CRUD的问题。 一 CRUD方式的问题 在以前的管理系统中,命令(Command,通常用来更新数据,操作DB)和查询(Query)通常使用的是在数据访问层中Repository中的实体对象(这些对象是对DB中表的映射),这些实体有可能是SQLServer中的一行数据或者多个表。 通常对DB执行的增,删,改,查(CRUD)都是针对的系统的实体对象。如通过数据访问层获取数据,然后通过数据传输对象DTO传给表现层。或者,用户需要更新数据,通过DTO对象将数据传给Model,然后通过数据访问层写回数据库,系统中的所有交互都是和数据查询和存储有关,可以认为是数据驱动(Data-Driven)的,如下图: 对于一些比较简单的系统,使用这种CRUD的设计方式能够满足要求。特别是通过一些代码生成工具及ORM等能够非常方便快速的实现功能。 但是传统的CRUD方法有一些问题: 使用同一个对象实体来进行数据库读写可能会太粗糙,大多数情况下,比如编辑的时候可能只需要更新个别字段,但是却需要将整个对象都穿进去,有些字段其实是不需要更新的。在查询的时候在表现层可能只需要个别字段,但是需要查询和返回整个实体对象。 使用同一实体对象对同一数据进行读写操作的时候,可能会遇到资源竞争的情况,经常要处理的锁的问题,在写入数据的时候,需要加锁。读取数据的时候需要判断是否允许脏读。这样使得系统的逻辑性和复杂性增加,并且会对系统吞吐量的增长会产生影响。 同步的,直接与数据库进行交互在大数据量同时访问的情况下可能会影响性能和响应性,并且可能会产生性能瓶颈。 由于同一实体对象都会在读写操作中用到,所以对于安全和权限的管理会变得比较复杂。 这里面很重要的一个问题是,系统中的读写频率比,是偏向读,还是偏向写,就如同一般的数据结构在查找和修改上时间复杂度不一样,在设计系统的结构时也需要考虑这样的问题。解决方法就是我们经常用到的对数据库进行读写分离。 让主数据库处理事务性的增,删,改操作(Insert,Update,Delete)操作,让从数据库处理查询操作(Select操作),数据库复制被用来将事务性操作导致的变更同步到集群中的从数据库。这只是从DB角度处理了读写分离,但是从业务或者系统上面读和写仍然是存放在一起的。他们都是用的同一个实体对象。 要从业务上将读和写分离,就是接下来要介绍的命令查询职责分离模式。 二 什么是CQRS CQRS最早来自于Betrand Meyer(Eiffel语言之父,开-闭原则OCP提出者)在 Object-Oriented Software Construction 这本书中提到的一种 命令查询分离 (Command Query Separation,CQS) 的概念。其基本思想在于,任何一个对象的方法可以分为两大类: 命令(Command):不返回任何结果(void),但会改变对象的状态。 查询(Query):返回结果,但是不会改变对象的状态,对系统没有副作用。 根据CQS的思想,任何一个方法都可以拆分为命令和查询两部分,比如:
1 |
private int i = 0; |
1 2 3 4 5 |
private int Increase(int value) { i += value; return i; } |
这个方法,我们执行了一个命令即对变量i进行相加,同时又执行了一个Query,即查询返回了i的值,如果按照CQS的思想,该方法可以拆成Command和Query两个方法,如下:
1 2 3 4 5 6 7 8 |
private void IncreaseCommand(int value) { i += value; } private int QueryValue() { return i; } |
操作和查询分离使得我们能够更好的把握对象的细节,能够更好的理解哪些操作会改变系统的状态。当然CQS也有一些缺点,比如代码需要处理多线程的情况。 CQRS是对CQS模式的进一步改进成的一种简单模式。 它由Greg Young在CQRS, Task Based UIs, Event Sourcing agh! 这篇文章中提出。“CQRS只是简单的将之前只需要创建一个对象拆分成了两个对象,这种分离是基于方法是执行命令还是执行查询这一原则来定的(这个和CQS的定义一致)”。 CQRS使用分离的接口将数据查询操作(Queries)和数据修改操作(Commands)分离开来,这也意味着在查询和更新过程中使用的数据模型也是不一样的。这样读和写逻辑就隔离开来了。 使用CQRS分离了读写职责之后,可以对数据进行读写分离操作来改进性能,可扩展性和安全。如下图: 主数据库处理CUD,从库处理R,从库的的结构可以和主库的结构完全一样,也可以不一样,从库主要用来进行只读的查询操作。在数量上从库的个数也可以根据查询的规模进行扩展,在业务逻辑上,也可以根据专题从主库中划分出不同的从库。从库也可以实现成ReportingDatabase,根据查询的业务需求,从主库中抽取一些必要的数据生成一系列查询报表来存储。 使用ReportingDatabase的一些优点通常可以使得查询变得更加简单高效: ReportingDatabase的结构和数据表会针对常用的查询请求进行设计。 ReportingDatabase数据库通常会去正规化,存储一些冗余而减少必要的Join等联合查询操作,使得查询简化和高效,一些在主数据库中用不到的数据信息,在ReportingDatabase可以不用存储。 可以对ReportingDatabase重构优化,而不用去改变操作数据库。 对ReportingDatabase数据库的查询不会给操作数据库带来任何压力。 可以针对不同的查询请求建立不同的ReportingDatabase库。 当然这也有一些缺点,比如从库数据的更新。如果使用SQLServer,本身也提供了一些如故障转移和复制机制来方便部署。 三 什么时候可以考虑CQRS CQRS模式有一些优点: 分工明确,可以负责不同的部分 将业务上的命令和查询的职责分离能够提高系统的性能、可扩展性和安全性。并且在系统的演化中能够保持高度的灵活性,能够防止出现CRUD模式中,对查询或者修改中的某一方进行改动,导致另一方出现问题的情况。 逻辑清晰,能够看到系统中的那些行为或者操作导致了系统的状态变化。 可以从数据驱动(Data-Driven) 转到任务驱动(Task-Driven)以及事件驱动(Event-Driven). 在下场景中,可以考虑使用CQRS模式: 当在业务逻辑层有很多操作需要相同的实体或者对象进行操作的时候。CQRS使得我们可以对读和写定义不同的实体和方法,从而可以减少或者避免对某一方面的更改造成冲突 对于一些基于任务的用户交互系统,通常这类系统会引导用户通过一系列复杂的步骤和操作,通常会需要一些复杂的领域模型,并且整个团队已经熟悉领域驱动设计技术。写模型有很多和业务逻辑相关的命令操作的堆,输入验证,业务逻辑验证来保证数据的一致性。读模型没有业务逻辑以及验证堆,仅仅是返回DTO对象为视图模型提供数据。读模型最终和写模型相一致。 适用于一些需要对查询性能和写入性能分开进行优化的系统,尤其是读/写比非常高的系统,横向扩展是必须的。比如,在很多系统中读操作的请求时远大于写操作。为适应这种场景,可以考虑将写模型抽离出来单独扩展,而将写模型运行在一个或者少数几个实例上。少量的写模型实例能够减少合并冲突发生的情况 适用于一些团队中,一些有经验的开发者可以关注复杂的领域模型,这些用到写操作,而另一些经验较少的开发者可以关注用户界面上的读模型。 对于系统在将来会随着时间不段演化,有可能会包含不同版本的模型,或者业务规则经常变化的系统 需要和其他系统整合,特别是需要和事件溯源Event Sourcing进行整合的系统,这样子系统的临时异常不会影响整个系统的其他部分。 但是在以下场景中,可能不适宜使用CQRS: 领域模型或者业务逻辑比较简单,这种情况下使用CQRS会把系统搞复杂。 对于简单的,CRUD模式的用户界面以及与之相关的数据访问操作已经足够的话,没必要使用CQRS,这些都是一个简单的对数据进行增删改查。 不适合在整个系统中到处使用该模式。在整个数据管理场景中的特定模块中CQRS可能比较有用。但是在有些地方使用CQRS会增加系统不必要的复杂性。 四 CQRS与Event Sourcing的关系 在CQRS中,查询方面,直接通过方法查询数据库,然后通过DTO将数据返回。在操作(Command)方面,是通过发送Command实现,由CommandBus处理特定的Command,然后由Command将特定的Event发布到EventBus上,然后EventBus使用特定的Handler来处理事件,执行一些诸如,修改,删除,更新等操作。这里,所有与Command相关的操作都通过Event实现。这样我们可以通过记录Event来记录系统的运行历史记录,并且能够方便的回滚到某一历史状态。Event Sourcing就是用来进行存储和管理事件的。这里不展开介绍。 五 CQRS的简单实现 CQRS模式在思想上比较简单,但是实现上还是有些复杂。它涉及到DDD,以及Event Sourcing,这里使用codeproject上的 Introduction to CQRS 这篇文章的例子来说明CQRS模式。这个例子是一个简单的在线记日志(Diary)系统,实现了日志的增删改查功能。整体结构如下: 上图很清晰的说明了CQRS在读写方面的分离,在读方面,通过QueryFacade到数据库里去读取数据,这个库有可能是ReportingDB。在写方面,比较复杂,操作通过Command发送到CommandBus上,然后特定的CommandHandler处理请求,产生对应的Event,将Eevnt持久化后,通过EventBus特定的EevntHandler对数据库进行修改等操作。 例子代码可以到codeproject上下载,整体结构如下: […]
View Details原版是从网上找了一位大神的,自己只是用了一点适合自己的。 具体实现 1.首先已经确认WPF中没有实现最小化托盘的类与方法,用到了winform中的程序集 using Drawing = System.Drawing; using Forms = System.Windows.Forms; 2.XAML的后代相应事件的Demo,只是为了看起来方便~!其中也包含了在任务栏中不现实图标,只在托盘中显示。双击实现窗口的还原。没用到大神写的,自己琢磨了个,令人想不到的蛋疼的后果还没出现,也就暂时这样了。
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 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 110 111 112 113 |
namespace 最小化到托盘 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { //妈蛋找了你一天,,启动后不现实任务栏图标!!!!!!!!!!!!!!!!!!!! this.ShowInTaskbar = false; InitializeComponent(); } /// <summary> /// 托盘右击菜单--上线按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_OnlineClick(object sender, EventArgs e) { MessageBox.Show("提示上线!"); } /// <summary> /// 托盘右击菜单--离开按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_LeaveClick(object sender, EventArgs e) { MessageBox.Show("提示暂时离开!"); } /// <summary> /// 托盘右击菜单--在忙按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_BusyClick(object sender, EventArgs e) { MessageBox.Show("提示在忙!"); } /// <summary> /// 托盘右击菜单--请勿打扰按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_NoBotherClick(object sender, EventArgs e) { MessageBox.Show("提示请勿打扰!"); } /// <summary> /// 托盘右击菜单--隐身按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_HideClick(object sender, EventArgs e) { MessageBox.Show("提示隐身!"); } /// <summary> /// 托盘右击菜单--离线按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_OffLineClick(object sender, EventArgs e) { MessageBox.Show("提示离线!"); } /// <summary> /// 托盘右击菜单--关于我们按钮 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MenuItem_AboutUsClick(object sender, EventArgs e) { MessageBox.Show("提示关于我们!"); } /// <summary> /// 托盘小图标的双击事件--最小化的状态下双击还原 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void NotificationAreaIcon_MouseDoubleClick_1(object sender, MouseButtonEventArgs e) { //if (e.ChangedButton==MouseButton.Left) //{ if (this.WindowState == WindowState.Minimized) { WindowState = WindowState.Normal; } // } } private void MenuItem_ExitClick(object sender, EventArgs e) { this.Close(); } private void Window_MouseMove_1(object sender, MouseEventArgs e) { } //以下代码想实现即时聊天的记住密码功能,度娘说要存入配置文件,没搞成功,希望看到的人帮我这个忙~ private void Button_Click_1(object sender, RoutedEventArgs e) { //点击按钮往配置文件存入信息 Configuration cfa = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); cfa.AppSettings.Settings["LogName"].Value = "123"; cfa.Save(); MessageBox.Show(ConfigurationManager.AppSettings["LogName"]); } } } |
3.最主要的是大神写的这个类,学习编程五个月,能看懂的不是太多,稍微明白点意思,但是说不上来,直接贴代码吧。以后在研究!
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 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 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows; using System.Windows.Input; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Threading; using Drawing = System.Drawing; using Forms = System.Windows.Forms; namespace 最小化到托盘 { /// <summary> /// Represents a thin wrapper for <see cref="Forms.NotifyIcon"/> /// </summary> [ContentProperty("Text")] [DefaultEvent("MouseDoubleClick")] public class NotificationAreaIcon : FrameworkElement { Forms.NotifyIcon notifyIcon; public static readonly RoutedEvent MouseClickEvent = EventManager.RegisterRoutedEvent( "MouseClick", RoutingStrategy.Bubble, typeof(MouseButtonEventHandler), typeof(NotificationAreaIcon)); public static readonly RoutedEvent MouseDoubleClickEvent = EventManager.RegisterRoutedEvent( "MouseDoubleClick", RoutingStrategy.Bubble, typeof(MouseButtonEventHandler), typeof(NotificationAreaIcon)); public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(ImageSource), typeof(NotificationAreaIcon)); public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(NotificationAreaIcon)); public static readonly DependencyProperty FormsContextMenuProperty = DependencyProperty.Register("MenuItems", typeof(List<Forms.MenuItem>), typeof(NotificationAreaIcon), new PropertyMetadata(new List<Forms.MenuItem>())); protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); // Create and initialize the window forms notify icon based notifyIcon = new Forms.NotifyIcon(); notifyIcon.Text = Text; if (!DesignerProperties.GetIsInDesignMode(this)) { notifyIcon.Icon = FromImageSource(Icon); } notifyIcon.Visible = FromVisibility(Visibility); if (this.MenuItems != null && this.MenuItems.Count > 0) { notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(this.MenuItems.ToArray()); } notifyIcon.MouseDown += OnMouseDown; notifyIcon.MouseUp += OnMouseUp; notifyIcon.MouseClick += OnMouseClick; notifyIcon.MouseDoubleClick += OnMouseDoubleClick; Dispatcher.ShutdownStarted += OnDispatcherShutdownStarted; } private void OnDispatcherShutdownStarted(object sender, EventArgs e) { notifyIcon.Dispose(); } private void OnMouseDown(object sender, Forms.MouseEventArgs e) { OnRaiseEvent(MouseDownEvent, new MouseButtonEventArgs( InputManager.Current.PrimaryMouseDevice, 0, ToMouseButton(e.Button))); } private void OnMouseUp(object sender, Forms.MouseEventArgs e) { OnRaiseEvent(MouseUpEvent, new MouseButtonEventArgs( InputManager.Current.PrimaryMouseDevice, 0, ToMouseButton(e.Button))); } private void OnMouseDoubleClick(object sender, Forms.MouseEventArgs e) { OnRaiseEvent(MouseDoubleClickEvent, new MouseButtonEventArgs( InputManager.Current.PrimaryMouseDevice, 0, ToMouseButton(e.Button))); } private void OnMouseClick(object sender, Forms.MouseEventArgs e) { OnRaiseEvent(MouseClickEvent, new MouseButtonEventArgs( InputManager.Current.PrimaryMouseDevice, 0, ToMouseButton(e.Button))); } private void OnRaiseEvent(RoutedEvent handler, MouseButtonEventArgs e) { e.RoutedEvent = handler; RaiseEvent(e); } public List<Forms.MenuItem> MenuItems { get { return (List<Forms.MenuItem>)GetValue(FormsContextMenuProperty); } set { SetValue(FormsContextMenuProperty, value); } } public ImageSource Icon { get { return (ImageSource)GetValue(IconProperty); } set { SetValue(IconProperty, value); } } public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } public event MouseButtonEventHandler MouseClick { add { AddHandler(MouseClickEvent, value); } remove { RemoveHandler(MouseClickEvent, value); } } public event MouseButtonEventHandler MouseDoubleClick { add { AddHandler(MouseDoubleClickEvent, value); } remove { RemoveHandler(MouseDoubleClickEvent, value); } } #region Conversion members private static Drawing.Icon FromImageSource(ImageSource icon) { if (icon == null) { return null; } Uri iconUri = new Uri(icon.ToString()); return new Drawing.Icon(Application.GetResourceStream(iconUri).Stream); } private static bool FromVisibility(Visibility visibility) { return visibility == Visibility.Visible; } private MouseButton ToMouseButton(Forms.MouseButtons button) { switch (button) { case Forms.MouseButtons.Left: return MouseButton.Left; case Forms.MouseButtons.Right: return MouseButton.Right; case Forms.MouseButtons.Middle: return MouseButton.Middle; case Forms.MouseButtons.XButton1: return MouseButton.XButton1; case Forms.MouseButtons.XButton2: return MouseButton.XButton2; } throw new InvalidOperationException(); } #endregion Conversion members } } |
from:https://www.cnblogs.com/gchlcc/p/4987042.html
View DetailsWPF程序也可以很轻松的实现类似QQ那样最小化到任务栏的功能。
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 33 34 35 36 37 38 |
WindowState ws; WindowState wsl; NotifyIcon notifyIcon; #region Constructions public MainWindow()();//显示托盘。 icon(); //保证窗体显示在上方。 wsl = WindowState; } #endregion private void icon() { this.notifyIcon = new NotifyIcon(); this.notifyIcon.BalloonTipText = "Hello, 文件监视器"; //设置程序启动时显示的文本 this.notifyIcon.Text = "文件监视器";//最小化到托盘时,鼠标点击时显示的文本 this.notifyIcon.Icon = new System.Drawing.Icon("Downloads.ico");//程序图标 this.notifyIcon.Visible = true; notifyIcon.MouseDoubleClick += OnNotifyIconDoubleClick; this.notifyIcon.ShowBalloonTip(1000); } private void OnNotifyIconDoubleClick(object sender, EventArgs e) { this.Show(); WindowState = wsl; } private void Window_StateChanged(object sender, EventArgs e) { ws = WindowState; if (ws == WindowState.Minimized) { this.Hide(); } } |
from:https://www.cnblogs.com/Gyoung/archive/2012/12/06/2805932.html
View Details让WPF应用最小到系统托盘?可以调用System.Windows.Forms.NotifyIcon来实现,下面是示例代码:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public partial class MainWindow : Window { private NotifyIcon notifyIcon; public MainWindow() { InitializeComponent(); this.notifyIcon = new NotifyIcon(); this.notifyIcon.BalloonTipText = "系统监控中... ..."; this.notifyIcon.ShowBalloonTip(2000); this.notifyIcon.Text = "系统监控中... ..."; this.notifyIcon.Icon = new System.Drawing.Icon(@"AppIcon.ico"); this.notifyIcon.Visible = true; //打开菜单项 System.Windows.Forms.MenuItem open = new System.Windows.Forms.MenuItem("Open"); open.Click += new EventHandler(Show); //退出菜单项 System.Windows.Forms.MenuItem exit = new System.Windows.Forms.MenuItem("Exit"); exit.Click += new EventHandler(Close); //关联托盘控件 System.Windows.Forms.MenuItem[] childen = new System.Windows.Forms.MenuItem[] { open, exit }; notifyIcon.ContextMenu = new System.Windows.Forms.ContextMenu(childen); this.notifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler((o, e) => { if (e.Button == MouseButtons.Left) this.Show(o, e); }); } private void Show(object sender, EventArgs e) { this.Visibility = System.Windows.Visibility.Visible; this.ShowInTaskbar = true; this.Activate(); } private void Hide(object sender, EventArgs e) { this.ShowInTaskbar = false; this.Visibility = System.Windows.Visibility.Hidden; } private void Close(object sender, EventArgs e) { System.Windows.Application.Current.Shutdown(); } } |
运行时发现,程序一定要能找到ICON,否则会报错,并且ICON还没包含到程序中,需要一个额外的ICON来做托盘图标。当然这个都是能解决的:
1 |
this.notifyIcon.Icon = new System.Drawing.Icon(@"AppIcon.ico"); |
将以上一句替换成下面内容,意思就是读取程序图标,来作为托盘图标
1 |
this.notifyIcon.Icon = System.Drawing.Icon.ExtractAssociatedIcon(System.Windows.Forms.Application.ExecutablePath); |
运行,搞定,这样你的程序就不用拖着一个ICON文件当累赘了。 from:https://www.cnblogs.com/ke10/archive/2012/11/16/NotifyIcon.html
View Details就本人而言,C#中关闭应用主要有以下途径: 1.Close():关闭当前窗口,可以在OnClosing和 OnClosed中捕获消息,在OnClosing的时候,可以取消关闭窗口 2.Application.Current.Shutdown()/App.Current.Shutdown(): 关闭当前程序,如果有其他线程没有结束,不会关闭 3.Environment.Exit(0):强制退出,即使有其他的线程没有结束 4.Process类的CloseMainWindow, Kill:Process.CloseMainWindow是GUI程序的最友好结束方式,从名字上就可以看出来它是通过结束主窗体,相当于用户点击窗体的关闭按钮或者按Alt + F4 5.Environment类的FailFast:这是最暴力最彻底最直接的方法,一般不建议使用 现对各方式做简单的介绍: Close():如过调用了Close,而在Closing中没有显示的取消退出,则系统可以退出,这种情况仅仅是在没有多余线程,没有其他窗口启动的时候,如果有其他窗口同时启动,则要考虑App.Current.ShutdownMode。 Application.Current.Shutdown()/App.Current.Shutdown():其使用讲究最多。 在WPF应用程序的关闭是有ShutdownMode属性设置,具有3中枚举类型的值: 1)OnLastWindowClose(默认值)—应用程序最后一个窗体关闭时关闭应用程序 2)OnMainWindowClose—应用程序主窗体关闭时关闭应用程序 3)OnExplicitShutdown—显示调用关闭 示例如下: <Application x:Class="TestApplication.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation%22 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml%22 StartupUri="Window1.xaml" ShutdownMode="OnMainWindowClose"> </Application> Environment.Exit(0):Environment.Exit相当于在Main函数中的return指令。不过它不会执行代码块的finally块(如果有的话),但资源清理还是要进行的。它是最常见的退出当前进程的方法之一。在Main函数中我们可以直接return语句便退出了程序。如果不在Main函数内,那么Environment.Exit方法就可以派上用场。 示例如下: private void CloseApp() { CloseSignal(); AppManager.Instance.Close(); Environment.Exit(0); } Environment类的FailFast:此方法更速度,它甚至不需要向操作系统返回进程退出代码(ExitCode),直接结束当前进程并在应用程序事件薄中写入信息,用于程序出现致命错误需要立即停止。 Process.Kill:从名字也可以看出来,直接杀掉,不给喘息喘息机会,Kill方法会直接结束整个进程,不进行常规资源清理(什么finally块等……)。Kill本质调用本地API:TerminateProcess函数。 from:http://blog.csdn.net/nncrystal/article/details/36422785
View DetailsWPF在样式定义和UI动画上面相对于以前的技术有了不少的提升,下面给出WPF技术实现钟表的效果: 1、Visual Studio新建一个WPF应用程序,命名为WpfClock,新建一个images文件夹,并准备一个钟表的背景图片和程序图标素材。 2、编辑MainWindow.xaml文件,对UI进行定制,代码如下(指针都是用Rectangle实现的,当然可以用图片代替):
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 33 34 35 36 37 38 39 40 |
<Window x:Class="WpfClock.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Margin="2" Height="327" Width="311" AllowsTransparency="True" WindowStyle="None" Background="Transparent" WindowStartupLocation="CenterScreen" Icon="images/clock.ico" ResizeMode="NoResize" Topmost="False" Opacity="1"> <Grid Width="300" Height="300" MouseLeftButtonDown="Grid_MouseLeftButtonDown"> <Image Source="images/backGround.png"></Image> <Label Name="lab商标" Foreground="White" Margin="0,0,0,211" HorizontalAlignment="Center" VerticalAlignment="Bottom" Height="Auto" Width="Auto" FontSize="13" >JackMoon</Label> <Label Name="lab创建时间" Foreground="White" Margin="0,91,0,0" HorizontalAlignment="Center" VerticalAlignment="Top" Height="Auto" Width="Auto">1987</Label> <!-- 秒针定义 --> <Rectangle Margin="150,0,149,150" Name="rectangleSecond" Stroke="White" Height="120" VerticalAlignment="Bottom" Width="1"> <Rectangle.RenderTransform> <RotateTransform x:Name="secondPointer" CenterX="0" CenterY="120" Angle="0" /> </Rectangle.RenderTransform> </Rectangle> <!-- --> <!-- 分钟定义 --> <Rectangle Margin="150,49,149,151" Name="rectangleMinute" Stroke="LightGreen" Width="1"> <Rectangle.RenderTransform> <RotateTransform x:Name="minutePointer" CenterX="0" CenterY="100" Angle="45" /> </Rectangle.RenderTransform> </Rectangle> <!-- --> <!-- 时针定义 --> <Rectangle Margin="150,80,149,150" Name="rectangleHour" Stroke="LightYellow" Width="1"> <Rectangle.RenderTransform> <RotateTransform x:Name="hourPointer" CenterX="0" CenterY="70" Angle="90" /> </Rectangle.RenderTransform> </Rectangle> <!----> <Label Content="08:08:08" FontSize="16" Foreground="White" Height="Auto" HorizontalAlignment="Center" Margin="114,0,113,86" Name="labTime" VerticalAlignment="Bottom" Width="Auto" /> </Grid> </Window> |
3、编辑MainWindow.xaml.CS文件,对后台逻辑进行定制,代码如下:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WpfClock { using System.Threading; using System.Windows.Threading; /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { //计时器 System.Timers.Timer timer = new System.Timers.Timer(1000); public MainWindow() { InitializeComponent(); #region 初始化时间 secondPointer.Angle = DateTime.Now.Second * 6; minutePointer.Angle = DateTime.Now.Minute * 6; hourPointer.Angle = (DateTime.Now.Hour * 30) + (DateTime.Now.Minute * 0.5); this.labTime.Content = DateTime.Now.ToString("HH:mm:ss"); #endregion timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); timer.Enabled = true; } private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { //进行拖放移动 this.DragMove(); } private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //UI异步更新 this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { //秒针转动,秒针绕一圈360度,共60秒,所以1秒转动6度 secondPointer.Angle = DateTime.Now.Second * 6; //分针转动,分针绕一圈360度,共60分,所以1分转动6度 minutePointer.Angle = DateTime.Now.Minute * 6; //时针转动,时针绕一圈360度,共12时,所以1时转动30度。 //另外同一个小时内,随着分钟数的变化(绕一圈60分钟),时针也在缓慢变化(转动30度,30/60=0.5) hourPointer.Angle = (DateTime.Now.Hour * 30)+ (DateTime.Now.Minute * 0.5); //更新时间值 this.labTime.Content = DateTime.Now.ToString("HH:mm:ss"); })); } } } |
4、编译运行,如果运气不错的话,应该能显示如下效果: 5、总结 WPF可以用RotateTransform中的Angle进行旋转,可以指定中心点(CenterX,CenterY)
1 2 3 |
<Rectangle.RenderTransform> <RotateTransform x:Name="hourPointer" CenterX="0" CenterY="70" Angle="90" /> </Rectangle.RenderTransform> |
from:https://www.cnblogs.com/isaboy/p/wpfclock.html
View Details