远程管理Demo(C#)

一个C#的通信的例子 1.服务端,服务端通过ip和端口生成客户端之后,点击开始监听后,便开启监听线程持续监听,同时注册断开连接和收到信息的事件。收到来自TcpClient 流中的信息后,解析之,如果是连接信息,就添加到连接列表,这样服务端就可以显示多个客户端了。如果是断开信息,就删掉。如果服务端想要给客户端发消息,就选中该客户,然后填写信息,就会调用连接类的发送方法。 2.客户端,也就是被控端,被控端通过tcp连接到远端ip,然后发送连接成功状态,随后异步读取。读取到信息后调用解析方式。然后处理。。 3.服务端如何生成客户端。其实也比较简单。就是写好客户端以后,保存为文本。然后通过CodeDomProvider的相关方法来编译即可。代码如下: public static bool Compile(string EXE_Name, string Source) { CodeDomProvider Compiler = CodeDomProvider.CreateProvider("CSharp"); CompilerParameters Parameters = new CompilerParameters(); CompilerResults cResults = default(CompilerResults); Parameters.GenerateExecutable = true; Parameters.OutputAssembly = EXE_Name; Parameters.ReferencedAssemblies.Add("System.dll"); Parameters.CompilerOptions = " /target:winexe"; Parameters.TreatWarningsAsErrors = false; cResults = Compiler.CompileAssemblyFromSource(Parameters, Source); if (cResults.Errors.Count > 0) { foreach (CompilerError CompilerError_loopVariable in cResults.Errors) { CompilerError error = CompilerError_loopVariable; MessageBox.Show("Error: " + error.ErrorText, "", MessageBoxButtons.OK, MessageBoxIcon.Error); } return false; } else if (cResults.Errors.Count == 0) { return true; } return true; } 源码下载:CSharp RAT Example.zip

2013-01-04 · 1 min · bystander

Lambda高手之路第五部分

武汉下雪了。。今天介绍Lambda表达式非常有用的情况。。ps:这个高手之路已经翻译了10000多字了。。疼啊。。 一些模式比另一些模式有时候更加合适,真正有用的模式是自定义方法表达式,用爱促使话一些对象的部分,我们考虑下面这种情况。 我们想要创建一个可以处理多种延迟加载的对象,这意味着即时对象已经被实例化了,我们还没有加载所有请求的资源,一个理由就是防止大量的IO操作。(比如通过网络传输),当我们开始使用数据的时候,我们想要确定数据足够新鲜,现在有一些确定的方法可以做这个。并且最有效的显然是实体框架已经用LINQ解决了延迟加载的问题,Iqueryable仅存储了查询,而没有任何无关的数据。一旦我们请求一个结果。不仅仅构造的查询被执行,同时也被以更高效的方式执行,比如一个在远程数据服务器上的SQL查询。 在这里,我们仅仅想要看看两种情况的不同点,首先,我们查询,一切就绪,查询应该在已经加载了的数据上进行。 class LazyLoad { public LazyLoad() { Search = query => { var source = Database.SearchQuery(query); Search = subquery => { var filtered = source.Filter(subquery); foreach(var result in filtered) yield return result; }; foreach(var result in source) yield return result; }; } public Func<string, IEnumerable<ResultObject>> Search { get; private set; } } 简单来看,这里我们有两种不他哦你的方法,地一个是我们把数据从数据库里提取出来(也就是Database静态类所做的),然后第二个方法将会过滤从数据库里提取出来的数据。一旦我们将会从我们的第一次查询取得结果,当然我们也可以构造内置的其他方法来重置类的行为,对于工业级的代码,其他的方法也许更加有用。 另一个例子是初始时间分支,假设我们有一个对象,该对象有个方法叫做Perform(),这个方法可以用来调用一些代码,包含这个方法的对象可以被初始化,初始化有三种方式。 通过传递方法来调用 通过传递一些包含这个方法的对象来调用 或者通过传递第一种情况下的序列化以后的信息来调用。 现在我们可以保留所有的三种方式做全局变量。而Perform方法将不得不查看当前的状态(或者是保存在枚举变量里,或者和null进行比较)然后检测被调用的正确的方式,最后调用开始。 更好的一种方法是吧Perform()方法写成一个属性,这个属性仅仅允许在类里面进行set,它是一个委托类型,现在我们可以在对应的构造方法里面直接设置这个属性,因此,我们可以不用全局变量,也不用担心这个对象是如何实例化的,这种方法更好。 看一小段简单的代码。 class Example { public Action<object> Perform { get; private set; } public Example(Action<object> methodToBeInvoked) { Perform = methodToBeInvoked; } //接口 public Example(IHaveThatFunction mother) { //传递的对象必须有我们要用的方法 Perform = mother.TheCorrespondingFunction; } public Example(string methodSource) { //Compile方法是任意的。 Perform = Compile(methodSource); } } 即时这个例子看起来如我们所愿被构造了。让阿尔。大多数情况下只使用前两种,但是随着领域特性语言,编译器,日志框架,数据访问层和其他很多情况下,通常有很多方式可以完成,但Lambda表达式也许是最优雅的。 考虑这种情况,我们可以在函数编程领域体会到即时调用方法表达式的好处,我们可以看到C#中IIFE的一种用法。用的不多。但是我认为真的很好。但不是用在这种情况下。 Func<double, double> myfunc; var firstValue = (myfunc = (x) => { return 2.0 * x * x - 0.5 * x; })(1); var secondValue = myfunc(2); //... 我们也可以使用即时调用方法来防止一些确定的非静态的方法被重复调用。这就会出现自定义方法和初始时间分支和IIFE的组合使用了。 下一节介绍一些新的Lambda设计模式

2012-12-27 · 1 min · bystander

3分钟理解Lambda表达式

1.什么是Lambda表达式 Lambda表达式是一个匿名方法,通常在LINQ中被用来创建委托 简单来说。它是一个没有声明,没有访问修饰符,没有返回值。甚至没有名字的方法。 2.为什么我们需要使用Lambda表达式?或者说为什么我们要写一个没有名字的函数? 为了方便,这种快捷方式允许你在调用的地方直接编写代码,尤其是你想调用的代码只会在这个地方使用一次。并且方法体本身很短。节省了单独写方法中写声明等等的麻烦。。 好处 1.代码量减少。不必写方法的名称。返回值和访问修饰符 2.当阅读代码的时候。直接就可以看到被调用函数的代码,不用去别的地方。 Lambda表示应该短些。太复杂了。可读性就下降了 如果编写Lambda表达式 Lambda基本的定义是:参数=>执行代码 举个例子 n = > n % 2 == 1 n是输入参数 n % 2 == 1 是函数体 你可以读作:给这个匿名方法传入一个参数n,如果n是奇数就返回true 使用该Lambda的例子 List<int> numbers = new List<int>{11,37,52}; List<int> oddNumbers = numbers.where(n => n % 2 == 1).ToList(); //现在oddNumbers 里面就是11和37了 ok.基本的Lambda表达式就是这样了。

2012-12-08 · 1 min · bystander

获取操作系统版本信息

坊间流传的代码都有些问题,比如不能正常获取win7以上的版本信息,不能获取诸如专业版,旗舰版等的信息,不能正常获取操作系统位的信息。 使用代码,写了一个简单的库来实现效果。用法大概如下: StringBuilder sb = new StringBuilder(String.Empty); sb.AppendLine("Operation System Information"); sb.AppendLine("----------------------------"); sb.AppendLine(String.Format("Name = {0}", OSVersionInfo.Name)); sb.AppendLine(String.Format("Edition = {0}", OSVersionInfo.Edition)); if (OSVersionInfo.ServicePack!=string.Empty) sb.AppendLine(String.Format("Service Pack = {0}", OSVersionInfo.ServicePack)); else sb.AppendLine("Service Pack = None"); sb.AppendLine(String.Format("Version = {0}", OSVersionInfo.VersionString)); sb.AppendLine(String.Format("ProcessorBits = {0}", OSVersionInfo.ProcessorBits)); sb.AppendLine(String.Format("OSBits = {0}", OSVersionInfo.OSBits)); sb.AppendLine(String.Format("ProgramBits = {0}", OSVersionInfo.ProgramBits)); textBox1.Text = sb.ToString(); 对比一下坊间的几种不足: 总的来说。最大的问题就是不能正确检测你的操作系统到底是32位还是64位。几种方法大致如下: 1. 使用IntPtr指针的大小 最关键的一句代码是: return IntPtr.Size * 8; 但是事实上,这个返回的不是操作系统的位数,返回的是运行的程序的位数,如果在64位的windows上以32位的模式运行了这个程序,那么就会返回32. 2. 使用PROCESSOR_ARCHITECTURE 环境变量 string pa = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); return ((String.IsNullOrEmpty(pa) || String.Compare(pa, 0, "x86", 0, 3, true) == 0) ? 32 : 64); 这就是纯粹的误导了,因为和1的情况一样。不能返回处理器的位数而是返回了运行程序的位数,如果在64位的windows上以32位的模式运行了这个程序,那么就会返回32. 3. 使用PInvoke 和 GetSystemInfo 注意:为了保持文章不要太长。。我没有包括PInvoke API的声明,(译者注:C#的互操作性嘛),但你可能在我提供的源代码里找到。 ProcessorArchitecture pbits = ProcessorArchitecture.Unknown; try { SYSTEM_INFO l_System_Info = new SYSTEM_INFO(); GetSystemInfo(ref l_System_Info); switch (l_System_Info.uProcessorInfo.wProcessorArchitecture) { case 9: // PROCESSOR_ARCHITECTURE_AMD64 pbits = ProcessorArchitecture.Bit64; break; case 6: // PROCESSOR_ARCHITECTURE_IA64 pbits = ProcessorArchitecture.Itanium64; break; case 0: // PROCESSOR_ARCHITECTURE_INTEL pbits = ProcessorArchitecture.Bit32; break; default: // PROCESSOR_ARCHITECTURE_UNKNOWN pbits = ProcessorArchitecture.Unknown; break; } } catch { Ignore } return pbits; 老问题,还是会返回运行程序的位数,而不是操作系统/处理器的位数。 4. 使用PInvoke和GetNativeSystemInfo 我看到过有人说上面的都不可信。可以使用GetNativeSystemInfo代替,代码和上面一样,只是把GetSystemInfo换成GetNativeSystemInfo就好。 ...

2012-11-23 · 2 min · bystander

依赖倒置原则和依赖注入模式

昨天读完了程杰的《大话设计模式》。。收获颇丰。深刻感到了设计模式的伟大。。对面向接口的编程也理解了不少。刚好看到codeproject上一篇将依赖倒置的。讲到了依赖注入的方式。仔细读了一下。翻译一遍加深认识。 高耦合的代码随着项目复杂性的不断增加,最终会变成一碗碗的意大利面条啦。。二者通常是软件设计上的问题,如果一个类对另一个类的实现了解太多。当该类改变的时候会引起更多的改变。这违反了依赖倒置原则 而松耦合的代码设计优良。随着时间流逝,代码复杂两增大,松耦合的好处会变得更加清晰,依赖注入模式是实现松耦合的一个好的办法,本文介绍在没有依赖注入容器的情况下实现依赖注入 GoF说了,依赖倒置的原则: 高层模块不应依赖于低层模块,他们都应该依赖于抽象 抽象不依赖细节,细节依赖抽象 刚开始写依赖倒置比较难,随着经验增长会有所改善,通过使高层模块依赖于抽象,依赖倒置成功解耦,依赖注入模式是该原则的一个实现。 通常我们写出如下的代码: public class Email { public void SendEmail() { // code } } public class Notification { private Email _email; public Notification() { _email = new Email(); } public void PromotionalNotification() { _email.SendEmail(); } } Notification类依赖Email类,这违反了DIP,而且当我们要发送短信/保存到数据库的时候,我们还要改变Notification类。 我们使用抽象类/接口解耦 public interface IMessageService { void SendMessage(); } public class Email : IMessageService { public void SendMessage() { // code } } public class Notification { private IMessageService _iMessageService; public Notification() { _iMessageService = new Email(); } public void PromotionalNotification() { _iMessageService.SendMessage(); } } IMessageService 是一个接口,而Notification 类只要调用接口的方法/属性就可以了 同时,我们把Email对象的构造移到Notification 类外面去。 依赖注入模式可以实现。通常有三种方式 构造器注入 属性注入 方法注入 构造器注入 最普遍的方式,当一个类需要另一个类的依赖的时候,我们通过构造函数来提供,现在我们这样写 public class Notification { private IMessageService _iMessageService; public Notification(IMessageService _messageService) { this._iMessageService = _messageService; } public void PromotionalNotification() { _iMessageService.SendMessage(); } } 有几个好处:1.构造函数实现很简单,Notification类需要知道的很少。想要创建Notification实例的时候看构造函数就可以知道需要什么信息了。因此实现了松耦合。 属性注入 属性注入/setter注入比较不常见,当依赖可有可无的时候很有用。我们暴露一个可写的属性,允许客户提供不同的依赖实现,比如这样。 public class Notification { public IMessageService MessageService { get; set; } public void PromotionalNotification() { if (MessageService == null) { // some error message } else { MessageService.SendMessage(); } } } 没有了构造函数。而用属性来替换,在PromotionalNotifications 方法里我们需要检查MessageService的值或者提供相应的服务。 ...

2012-11-21 · 1 min · bystander

理解并实现模板模式

介绍 本文实现模板模式 背景 有时候我们需要做很多任务,而做这些任务的算法可能不同,这样可以设计成策略模式,这样。执行该任务的基本的一些代码就是一样的。但程序可可以动态的切换来执行任务的不同部分了。 现在,真实的情况是有些算法,从实现层面山看,有可能有一些步骤是不一样的,这种情况下。我们可以使用继承来完成。 当有个算法,而这个算法的一部分却多样的时候。使用模板模式就很好。GoF定义模板模式为: “Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.”. 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 在上面的类图中: AbstractClass:包含两种方法。第一种就是算法的每一步。另一种就是模板方法。模板方法就是那些可以被用在所有独立方法中。并且提供了算法执行的一个骨架 ConcreteClass:这个类重写了抽象类中每一步的方法,包含对这些步骤的个性化实现。 使用代码 看一个简单的例子。假想我们有一个类用来读取数据。并且能够为信息管理系统到处数据。 abstract class DataExporter { // 这个方法都是一致的 public void ReadData() { Console.WriteLine("Reading the data from SqlServer"); } // 当报表格式顶的时候这个也是定的。 public void FormatData() { Console.WriteLine("Formating the data as per requriements."); } // 目标文件类型的不同导致该方法不同 public abstract void ExportData(); // 这是客户端可能使用的模板方法 public void ExportFormatedData() { this.ReadData(); this.FormatData(); this.ExportData(); } } ReadData和FormatData 的实现不会变。唯一可变的部分就是ExportData方法。该方法对于不同的导出类型不同。如果我们要导出excel文件。我们要实现一个ConcreteClass的实现。 class ExcelExporter : DataExporter { public override void ExportData() { Console.WriteLine("Exporting the data to an Excel file."); } } 同样如果要导出PDF文件。重写这部分即可 class PDFExporter : DataExporter { public override void ExportData() { Console.WriteLine("Exporting the data to a PDF file."); } } 好处就是客户端可以使用DataExporter类,而具体的实现是在派生类中的 static void Main(string[] args) { DataExporter exporter = null; //导出 Excel文件 exporter = new ExcelExporter(); exporter.ExportFormatedData(); Console.WriteLine(); // 导出 PDF 文件 exporter = new PDFExporter(); exporter.ExportFormatedData(); } 运行时。对算法的调用将会执行真正请求的派生类的方法。 看一下我们的类图 ...

2012-10-25 · 1 min · bystander

Android开发获取Map API Key

地图应用使用com.google.android.maps这个包。通过MapView控件使用。但是之前需要申请一个用于开发的API Key,这个key会和当前的计算机用户绑定。然后通过这个key去官方申请就可以拿到一个开发用的api key了 <1>首先找到用户的debug.keystore文件,可以再”运行“里面搜debug.keystore;如:c:\users\Administrator.android\debug.keystore <2>接下来获取MD5指纹,网上很多说的有误。貌似新版默认是出现sha1加密的。通过添加-v 参数会显示所有。 首先运行cmd,在dos界面里,输入 keytool -list -v -keystore c:\users\Bystander\.android\debug.keystore 命令,然后会让你输入keystore密码, 输入:android,之后,会出现指纹认证MD5,如下: <3>去官方生成真正的api key 访问 Sign Up for the Android Maps API 输入那串值,同意条款,确定后要求用Google帐号登录。然后会拿到一个key。ok

2012-10-21 · 1 min · bystander

模拟Office2010文件菜单的TabControl模板

这是Office2010中的文件菜单点开后的效果。本文我将以强大的WPF来实现类似的效果。希望你能有所收获。而不是只拷贝/粘贴代码而已。 开始之前。先把TabControl找个地方放着。 <Window x:Class="TestClient.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <TabControl Name="tabSteps"> <TabItem Header="Info" IsSelected="True"> <TextBlock>Info content</TextBlock> </TabItem> <TabItem Header="Recent"> <TextBlock>Recent content tab</TextBlock> </TabItem> <TabItem Header="New"> <TextBlock>New content tab</TextBlock> </TabItem> <TabItem Header="Print"> <TextBlock>Print content tab</TextBlock> </TabItem> <TabItem Header="Save &amp; Send"> <TextBlock>Save &amp; send content tab</TextBlock> </TabItem> <TabItem Header="Help"> <TextBlock>Help tab</TextBlock> </TabItem> </TabControl> </Window> 然后会大概是这个效果 为了改变TabControl的显示效果。我们使用模板机制,我们把模板写进一个资源字典里。这样就可以重用了。添加一个资源字典的步骤如下 右键点击工程-添加-资源字典 然后在资源字典里添加一些代码。 <ControlTemplate x:Key="OfficeTabControl" TargetType="{x:Type TabControl}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="160" /> <ColumnDefinition/> </Grid.ColumnDefinitions> <Border Background="#FFE9ECEF" Grid.Column="0" BorderBrush="LightGray" BorderThickness="1" SnapsToDevicePixels="True" /> <StackPanel IsItemsHost="True" Grid.Column="0" Margin="0,0,-1,0" SnapsToDevicePixels="True" /> <ContentPresenter Content="{TemplateBinding SelectedContent}" Grid.Column="1" Margin="15,0,0,0" /> </Grid> </ControlTemplate> 这样就添加了一个有一个grid元素的名为OfficeTabControl的控件模板 . Grid 被分成两列,一列是标签页,一列是页内容。左边的列包含一个灰色背景和亮灰色的边缘线,然后一个StackPanel,IsItemsHost属性被设置为true, 这样标签项被会放在这个栈面板里。第二列是ContentPresenter 这会放置标签页内容。然后让我们前面的TabControl使用新模板。设置Template 属性。 <Window.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="OfficeTab.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Window.Resources> <TabControl Name="tabSteps" Template="{StaticResource OfficeTabControl}"> 在这之前,先把资源字典加到窗体的Reesouce里。然后再设置。然后运行软件。效果会有一些不一样。 然后要修改左侧单个标签的显示效果。通过改变模板来实现。给模板添加如下的代码 <ControlTemplate x:Key="OfficeTabControl" TargetType="{x:Type TabControl}"> <ControlTemplate.Resources> <Style TargetType="{x:Type TabItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TabItem}"> <Grid SnapsToDevicePixels="True"> <ContentPresenter Name="buttonText" Margin="15,0,5,0" TextBlock.FontFamily="Calibri" TextBlock.FontSize="12pt" TextBlock.Foreground="Black" Content="{TemplateBinding Header}" VerticalAlignment="Center"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ControlTemplate.Resources> 然后再运行 VisualState很有意思。我们可以放在Grid里。然后设置正常状态和鼠标悬停的状态。 为了添加鼠标悬停效果,我们添加两个Borders元素。一个右边缘是灰线,另一个用在背景上。亮蓝色放在上下边缘 <Border Name="hoverShape" Height="40" Margin="0,0,1,0" SnapsToDevicePixels="True" BorderThickness="0,0,1,0" BorderBrush="LightGray"> <Border BorderBrush="#FFA1B7EA" BorderThickness="0,1" Background="#FFE5EEF9" Height="40" SnapsToDevicePixels="True" /> </Border> 之后,我们为VisualState创建故事板,一个是正常状态。会使得hoverShape的透明度为0.另一个是鼠标悬停的状态。透明度会变成1 <Grid SnapsToDevicePixels="True"> <VisualStateManager.VisualStateGroups> <VisualStateGroup Name="CommonStates"> <VisualState Name="MouseOver"> <Storyboard> <DoubleAnimation Storyboard.TargetName="hoverShape" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:.1"/> </Storyboard> </VisualState> <VisualState Name="Normal"> <Storyboard> <DoubleAnimation Storyboard.TargetName="hoverShape" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:.1"/> </Storyboard> </VisualState> </VisualStateGroup> 之后效果如下 ...

2012-10-17 · 2 min · bystander

如何创建WPF用户控件&在WPF项目中使用

作者给的Demo我合并了下。VS2010直接打开解决方案。二者都有。 介绍 本文展示在WPF中如何创建用户控件并且如果在WPF项目中使用。我将使用VS2008和C#来展示如何创建一个自定义的ToolTip 背景 这篇由Sacha Barber.写的和我的有点像。 使用代码 开始。首先,我们创建一个用户控件。因此,我们选择新建WPF用户控件类库(WPF User Control Library)。 现在。我们可以创建或者编辑XAML代码来创建自定义的用户控件了。我使用XAML来创建自定义的ToolTip。你想做什么随你。 <UserControl Name="UserControlToolTip" x:Class="CustomToolTip.UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" RenderTransformOrigin="0,0" HorizontalAlignment="Left" VerticalAlignment="Top" > <UserControl.RenderTransform> <TransformGroup> <ScaleTransform ScaleX="1" ScaleY="1"/> <SkewTransform AngleX="0" AngleY="0"/> <RotateTransform Angle="0"/> <TranslateTransform x:Name="UserControlToolTipXY" X="0" Y="0"/> </TransformGroup> </UserControl.RenderTransform> <Grid HorizontalAlignment="Center" VerticalAlignment="Center" MinWidth="200" MinHeight="120"> <Grid.RowDefinitions> <RowDefinition Height="0.333*"/> <RowDefinition Height="0.667*"/> </Grid.RowDefinitions> <Rectangle Fill="#FFFBFBFB" Stroke="#FF000000" RadiusX="10" RadiusY="10" RenderTransformOrigin="0.139,0.012" StrokeThickness="1" Grid.RowSpan="2"> <Rectangle.BitmapEffect> <DropShadowBitmapEffect Opacity="0.8"/> </Rectangle.BitmapEffect> </Rectangle> <Rectangle RadiusX="10" RadiusY="10" RenderTransformOrigin="0.139,0.012" StrokeThickness="10" Stroke="{x:Null}" Margin="1,1,1,1" Grid.Row="0" Grid.RowSpan="2"> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0.725"> <GradientStop Color="#00E6D9AA" Offset="0.487"/> <GradientStop Color="#FFE6D9AA" Offset="0.996"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle RadiusX="10" RadiusY="10" RenderTransformOrigin="0.493,0.485" StrokeThickness="10" Stroke="{x:Null}" Grid.RowSpan="2" Margin="1,1,1,1"> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.014,0.5" StartPoint="0.211,0.5"> <GradientStop Color="#00E6D9AA" Offset="0.513"/> <GradientStop Color="#FFE6D9AA" Offset="0.996"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle RadiusX="10" RadiusY="10" RenderTransformOrigin="0.493,0.485" StrokeThickness="10" Stroke="{x:Null}" Grid.RowSpan="2" Margin="1,1,1,1"> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.493,0.002" StartPoint="0.493,0.33"> <GradientStop Color="#00E6D9AA" Offset="0.513"/> <GradientStop Color="#FFE6D9AA" Offset="0.996"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle RadiusX="10" RadiusY="10" RenderTransformOrigin="0.493,0.485" StrokeThickness="10" Stroke="{x:Null}" Grid.RowSpan="2" Margin="1,1,1,1"> <Rectangle.Fill> <LinearGradientBrush EndPoint="0.99,0.441" StartPoint="0.794,0.441"> <GradientStop Color="#00E6D9AA" Offset="0.513"/> <GradientStop Color="#FFE6D9AA" Offset="0.996"/> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <TextBlock Text="TextBlock" TextWrapping="Wrap" x:Name="TextBlockToolTip" RenderTransformOrigin="0.5,0.5" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="20,0,0,20" /> <TextBlock Name="ToolTipTitle" HorizontalAlignment="Stretch" Margin="15,16,15,6.1" FontSize="14" Text="title" d:LayoutOverrides="Height" /> </Grid> </UserControl> 同时。我们需要添加一些方法和属性来控制这些元素。 namespace CustomToolTip { public partial class UserControl1 : UserControl { public UserControl1() { InitializeComponent(); } public double UserControlToolTipX { get { return this.UserControlToolTipXY.X; } set { this.UserControlToolTipXY.X = value; } } public double UserControlToolTipY { get { return this.UserControlToolTipXY.Y; } set { this.UserControlToolTipXY.Y = value; } } public string UserControlTextBlockToolTip { get { return TextBlockToolTip.Text; } set { TextBlockToolTip.Text = value; } } public string UserControlToolTipTitle { get { return ToolTipTitle.Text; } set { ToolTipTitle.Text = value; } } } } ...

2012-10-14 · 3 min · bystander

WPF绘制圆角多边形

介绍 最近,我发现我需要个圆角多边形。而且是需要在运行时从用户界面来绘制。WPF有多边形。但是不支持圆角。我搜索了一下。也没找到可行的现成例子。于是就自己做吧。本文描述了圆角多边形的实现,也包括如何用在你的项目里。在Demo里面的RoundedCornersPolygon 类是完整的实现。 下载的Demo包括两部分 1. 通过XAML绘制圆角多边形 2. 运行时创建圆角多边形 背景 多边形可以被认为是沿着一个给定半径的圆的边缘和一些指定点/边。所构成的点的集合。 在WPF中。你可以给Polygon对象的Points属性添加一系列的点来制作多边形。 XAML方式 <Canvas> <Polygon Points="10,50 180,50 180,150 10,150" StrokeThickness="1" Stroke="Black" /> </Canvas> C#方式 var cnv = new Canvas(); var polygon = new Polygon {StrokeThickness = 1, Fill = Brushes.Black}; polygon.Points.Add(new Point(10, 50)); polygon.Points.Add(new Point(180, 50)); polygon.Points.Add(new Point(180, 150)); polygon.Points.Add(new Point(10, 150)); cnv.Children.Add(polygon); this.Content = cnv; 上面两个例子会输出下面的矩形 使用代码 我写的RoundedCornersPolygon 类和普通的多边形类很相似。但是有更多的属性来控制圆角。首先。看一个例子。展示一下圆角矩形类的使用 XAML方式 <Canvas> <CustomRoundedCornersPolygon:RoundedCornersPolygon Points="10,50 180,50 180,150 10,150" StrokeThickness="1" Stroke="Black" ArcRoundness="25" UseAnglePercentage="False" IsClosed="True"/> <Canvas> C#方式 var cnv = new Canvas(); var roundedPolygon = new RoundedCornersPolygon { Stroke = Brushes.Black, StrokeThickness = 1, ArcRoundness = 25, UseAnglePercentage = false, IsClosed = true }; roundedPolygon.Points.Add(new Point(10, 50)); roundedPolygon.Points.Add(new Point(180, 50)); roundedPolygon.Points.Add(new Point(180, 150)); roundedPolygon.Points.Add(new Point(10, 150)); cnv.Children.Add(roundedPolygon); this.Content = cnv; 输出如下: 多边形有四个主要属性 ArcRoundness 属性指定了从距离LineSegment终点多远的距离开始弯曲,通常和UseRoundnessPercentage 一起使用。UseRoundnessPercentage属性指定了ArcRoundness 值是百分比还是一个固定的值。 举个例子。ArcRoundness 被设置成10,而且UseRoundnessPercentage 被设置成false,那么弯曲将会在距离线段终点10的地方开始。而如果UseRoundnessPercentage 被设置成ture。则会是从线段终点10%的地方开始弯曲。 /// <summary> /// Gets or sets a value that specifies the arc roundness. /// </summary> public double ArcRoundness { get; set; } /// <summary> /// Gets or sets a value that specifies if the ArcRoundness property /// value will be used as a percentage of the connecting segment or not. /// </summary> public bool UseRoundnessPercentage { get; set; } IsClosed 指定多边形的最后一个点是否和第一个点闭合。为了成为一个多边形。一般应该被设置为true ...

2012-10-13 · 3 min · bystander