一、背景

  做项目时总是少不了Button,但是普通的Button大家都不喜欢用,总是想要自定义的Button,正好项目中用到不要边框的Button,并且是形状也是根据功能不同而变化的,并且窗口程序是会放大缩小的,如果用图片形式是会出现失真的,并且切换主题时没法变色,当然你可以用多个尺寸的图片,并且每个主题配一套图片,但是很麻烦。

二、实现

  以设置按钮为例,当然这里的颜色可能和你需要的不一样,但是没关系是可以自定义的

  思路是写一个Usercontrol,继承自Button,然会应用一个样式,这里不直接用样式而是用Usercontrol是因为加了几个DependencyProperty,这样就可以自定义颜色了

  Xaml代码

 <Button x:Class="PathButton.PathButton"
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"
Style="{DynamicResource PathButtonStyle}"
d:DesignHeight=""
d:DesignWidth=""
mc:Ignorable="d">
<Button.Resources>
<Style x:Key="FocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin=""
SnapsToDevicePixels="true"
Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"
StrokeDashArray="1 2"
StrokeThickness="" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="PathButtonStyle"
TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}" />
<Setter Property="Background" Value="#00000000" />
<Setter Property="BorderBrush" Value="#00000000" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="BorderThickness" Value="0,1,1,1" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Padding" Value="" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="true">
<Path x:Name="Path"
Data="{Binding PathData}"
Fill="{Binding DefaultFillBrush}"
RenderTransformOrigin="0.5,0.5"
Stretch="Uniform" />
</Border> <ControlTemplate.Triggers>
<Trigger Property="IsDefaulted" Value="True">
<Setter TargetName="Path" Property="Fill" Value="{Binding DefaultFillBrush}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Path" Property="Fill" Value="{Binding MouseOverBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Path" Property="Fill" Value="{Binding IsPressedBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Path" Property="Fill" Value="{Binding IsEnabledBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Resources> </Button>

  后台代码

 public partial class PathButton : Button
{
public Geometry PathData
{
get { return (Geometry)GetValue(PathDataProperty); }
set { SetValue(PathDataProperty, value); }
} // Using a DependencyProperty as the backing store for PathData. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PathDataProperty =
DependencyProperty.Register("PathData", typeof(Geometry), typeof(PathButton), new PropertyMetadata(new PathGeometry())); public Brush DefaultFillBrush
{
get { return (Brush)GetValue(DefaultFillBrushProperty); }
set { SetValue(DefaultFillBrushProperty, value); }
} // Using a DependencyProperty as the backing store for DefaultFillBrush. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DefaultFillBrushProperty =
DependencyProperty.Register("DefaultFillBrush", typeof(Brush), typeof(PathButton), new PropertyMetadata(Brushes.DarkGray)); public Brush MouseOverBrush
{
get { return (Brush)GetValue(MouseOverBrushProperty); }
set { SetValue(MouseOverBrushProperty, value); }
} // Using a DependencyProperty as the backing store for MouseOverBrush. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MouseOverBrushProperty =
DependencyProperty.Register("MouseOverBrush", typeof(Brush), typeof(PathButton), new PropertyMetadata(Brushes.DeepSkyBlue)); public Brush IsPressedBrush
{
get { return (Brush)GetValue(IsPressedBrushProperty); }
set { SetValue(IsPressedBrushProperty, value); }
} // Using a DependencyProperty as the backing store for IsPressedBrush. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsPressedBrushProperty =
DependencyProperty.Register("IsPressedBrush", typeof(Brush), typeof(PathButton), new PropertyMetadata(Brushes.DodgerBlue)); public Brush IsEnabledBrush
{
get { return (Brush)GetValue(IsEnabledBrushProperty); }
set { SetValue(IsEnabledBrushProperty, value); }
} // Using a DependencyProperty as the backing store for IsEnabledBrush. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsEnabledBrushProperty =
DependencyProperty.Register("IsEnabledBrush", typeof(Brush), typeof(PathButton), new PropertyMetadata(Brushes.LightGray)); public PathButton()
{
InitializeComponent();
DataContext = this;
}
}

  用法  

<pathButton:PathButton x:Name="Button"
Width="50"
Height="50"
PathData="M31.679651,15.723C22.841078,15.723 15.677,22.887022 15.677,31.724249 15.677,40.562878 22.841078,47.727002 31.679651,47.727002 40.518124,47.727002 47.682003,40.562878 47.682003,31.724249 47.682003,22.887022 40.518124,15.723 31.679651,15.723z M25.174641,0L30.947304,8.1649995 30.977009,8.163671C31.891628,8.1361193,32.811726,8.1617675,33.732849,8.2423577L34.116646,8.2807278 40.096367,0.5289996 49.181995,4.5158782 47.510448,14.236901 47.626137,14.339919C48.479649,15.11912,49.268909,15.955267,49.990528,16.839653L50.234638,17.14785 60.403648,15.836 64.007996,25.079203 55.322643,31.217757 55.324234,31.258986C55.34618,32.174153,55.314838,33.094563,55.22847,34.015755L55.226952,34.030385 63.345997,40.294331 59.359104,49.380002 49.249798,47.645153 49.143776,47.764214C48.695721,48.255009,48.228832,48.72456,47.744774,49.172226L47.324875,49.549786 48.723995,60.394425 39.48156,64 33.403603,55.403061 33.023663,55.43042C32.149929,55.481137,31.270197,55.483376,30.38839,55.435608L29.679308,55.383191 23.130268,63.875 14.041999,59.886834 15.844025,49.393521 15.71986,49.282948C15.207753,48.815411,14.718776,48.32737,14.253661,47.820706L13.803129,47.315312 3.612031,48.630002 0.0080004195,39.385499 8.0905037,33.673707 8.0481892,33.048829C7.9875851,31.908507,8.0095654,30.758269,8.1175261,29.606822L8.1191311,29.59272 0,23.328246 3.9867127,14.242 14.093521,15.978928 14.104487,15.966273C15.033746,14.935561,16.045525,13.997155,17.124784,13.156928L17.159048,13.131042 15.929999,3.6040602z"
DefaultFillBrush="Red"
MouseOverBrush="Yellow"
IsPressedBrush="Blue"
IsEnabledBrush="Black"/>

  这样就完成了,你只需要给一个你Path就可以显示你想要的按钮了,如果想改变颜色就设置下3个Brush就可以

三、效果

  默认样式  鼠标进入  鼠标按下

Tips:可以在 nuget 里搜索 PathButton 安装使用啦

自定义一个WPF的PathButton的更多相关文章

  1. [WPF 自定义控件]自定义一个“传统”的 Validation.ErrorTemplate

    1. 什么是Validaion.ErrorTemplate 数据绑定模型允许您将与您Binding的对象相关联ValidationRules. 如果用户输入的值无效,你可能希望在应用程序 用户界面 ( ...

  2. 使用 DotNet CLI 创建自定义的 WPF 项目模板

    描述 当我们安装完 DotNetCore 3.0 版本的 SDK 后,我们就可以创建基于 DotNetCore 的 WPF 项目模板,通过如下 CLI 可以方便快捷的创建并运行我们的项目: dotne ...

  3. 搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)

    搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 原文地址(英文):http://www.networkcomms.net/creating ...

  4. SpringMVC 自定义一个拦截器

    自定义一个拦截器方法,实现HandlerInterceptor方法 public class FirstInterceptor implements HandlerInterceptor{ /** * ...

  5. 一个WPF控件 诡异的MouseEvent 。

    背景: private System.Windows.Controls.Border _borderTouch; private bool _mouseDown = false;  private S ...

  6. jQuery Validate 表单验证插件----自定义一个验证方法

    一.下载依赖包 网盘下载:https://yunpan.cn/cryvgGGAQ3DSW  访问密码 f224 二.引入依赖包 <script src="../../scripts/j ...

  7. Spring自定义一个拦截器类SomeInterceptor,实现HandlerInterceptor接口及其方法的实例

    利用Spring的拦截器可以在处理器Controller方法执行前和后增加逻辑代码,了解拦截器中preHandle.postHandle和afterCompletion方法执行时机. 自定义一个拦截器 ...

  8. JSTL,自定义一个标签的功能案例

    1.自定义一个带有两个属性的标签<max>,用于计算并输出两个数的最大值: 2.自定义一个带有一个属性的标签<lxn:readFile  src=“”>,用于输出指定文件的内容 ...

  9. WPF入门教程系列(一) 创建你的第一个WPF项目

    WPF入门教程系列(一) 创建你的第一个WPF项目 WPF基础知识 快速学习绝不是从零学起的,良好的基础是快速入手的关键,下面先为大家摞列以下自己总结的学习WPF的几点基础知识: 1) C#基础语法知 ...

随机推荐

  1. 判断某个对象是不是DOM对象

    在写js代码时有时需要判断某个对象是不是DOM对象,然后再进行后续的操作,这里我给出一种兼容各大浏览器,同时又算是比较稳妥的一种方法. 要判断一个对象是否DOM对象,首先想到的无非就是它是否具有DOM ...

  2. Jmeter参数化的4种方法

    用Jmeter测试时包含两种情况的参数,一种是在url中,一种是请求中需要发送的参数. URL中的参数,如:http://blog.da-fang.com/index.php/2010/06/01/j ...

  3. Oracle基础 (十一)字符串函数

    一.字符串函数 LENGTH(char1,char2) SELECT LENGTH('abc def gh') FROM dual; --获取字符串的长度,包含空格 结果: CONCAT(char1, ...

  4. freeCodeCamp:Sorted Union

    写一个 function,传入两个或两个以上的数组,返回一个以给定的原始数组排序的不包含重复值的新数组. 换句话说,所有数组中的所有值都应该以原始顺序被包含在内,但是在最终的数组中不包含重复值. 非重 ...

  5. JS内存泄漏 和Chrome 内存分析工具简介(摘)

    原文地址:http://web.jobbole.com/88463/ JavaScript 中 4 种常见的内存泄露陷阱   原文:Sebastián Peyrott 译文:伯乐在线专栏作者 - AR ...

  6. ASP.NET发布WebService

    1. 创建一个空的Web应用程序 2. 再添加一个Web服务 3. 在所创建Web服务内,编写一算法 4. 写完可直接运行查看结果 5. 项目->右键,发布此WebService 6.  发布至 ...

  7. SSH项目中,解决中文请求参数乱码,Filter过滤器不起作用的问题

    1.web.xml配置如下(必须放在Struts2配置之前) <!-- 字符编码过滤器配置--> <filter> <filter-name>CharEncodin ...

  8. Oracle数据库对象_视图

    视图是一种非常重要的数据库对象,它的形式类似于普通表,我们可以从视图中查询数据. 实际上它是建立在表上的一种虚表,在视图中并不存储真正的数据,而是仅仅保存一条SELECT语句,对视图的访问将被转化为对 ...

  9. tcpServer 浅显的发一代码

    接下来发出来的一段代码也是我从网上找的一个例子,具体的来源已经找不到了,跟作者说声抱歉 ,现在公司做机票,出于性能的原因,就重写一个底层的tcp请求(不是我写的) 下面测试的是个控制台应用程序 Htt ...

  10. HashSet 读后感

    HashSet实现Set,是一个不能重复元素的集合,内部使用HashMap实现.因此具有HashMap的特性,如不保证元素插入的顺序,线程不安全,允许null.HashSet的元素就是内部HashMa ...