文章默认你已经入门WPF了

​ WPF日常开发,经常遇到默认的控件功能不满足需求,怎么办?

No1. 自定义控件模板

​ 平时开发中,经常遇到比较”俗“的需求,嫌弃控件默认的样子。怎么办?哈哈,那就整个容呗..... !

还记得心灵深处的Button吗?是不是第一印象就是规规矩矩的长方形,好了,这次我们俗一下,把它变成圆形!

上代码:

<Button Content="Test1" Width="80" Height="80" FocusVisualStyle="{x:Null}" Background="LightSeaGreen" BorderBrush="DarkBlue">
<Button.Template>
<ControlTemplate TargetType="ButtonBase">
<Grid>
<Ellipse x:Name="ellipseBorder" StrokeThickness="1" Stroke="{TemplateBinding BorderBrush}" Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" Value="Orange" TargetName="ellipseBorder"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Stroke" Value="OrangeRed" TargetName="ellipseBorder"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>

上外表:

No2. 重写控件

​ 很多情况下,并不是把控件换个外貌就可以解决的,我们不仅要改变外貌,还要改变控件的功能,比如说我们经常用的TextBox控件,正常的功能就是用来输入的,但更人性化点,我们想要TextBox能告诉我们当前的文本框应该输入用户名呢,还是地址呢等等。其实这个就是我们经常看到的水印功能,水印文字肯定要能按需设置,那我们不可能简单的通过改变下控件模板就可以解决的。

​ 通过需求我们知道,新的带水印的文本框,至少有个水印这么个依赖属性,供外部设置。当然新的带水印文本框和TextBox大概的样子差不多,但我们也要为新的控件定义外貌。

​ 所以第一步,先定义控件的功能,上代码:

public class WaterMarkTextBox : TextBox
{
static WaterMarkTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(WaterMarkTextBox), new FrameworkPropertyMetadata(typeof(WaterMarkTextBox)));
} public string WaterMark
{
get { return (string)GetValue(WaterMarkProperty); }
set { SetValue(WaterMarkProperty, value); }
} // Using a DependencyProperty as the backing store for WaterMark. This enables animation, styling, binding, etc...
public static readonly DependencyProperty WaterMarkProperty =
DependencyProperty.Register("WaterMark", typeof(string), typeof(WaterMarkTextBox), new PropertyMetadata(null)); }

​ 第二步,再定义控件的样子,上代码:

<Style TargetType="{x:Type local:WaterMarkTextBox}">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:WaterMarkTextBox}">
<Grid>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
<ScrollViewer x:Name="PART_ContentHost"
Grid.Column="0"
Margin="0"
Padding="{TemplateBinding Padding}"
VerticalAlignment="Stretch"
Background="{x:Null}"
BorderThickness="0"
IsTabStop="False"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<TextBlock x:Name="PART_Message"
Margin="4 0"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="Center"
Foreground="Gray"
Text="{TemplateBinding WaterMark}"
Visibility="Collapsed" />
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
<Setter TargetName="PART_Message" Property="Visibility" Value="Visible" />
</DataTrigger>
</ControlTemplate.Triggers> </ControlTemplate>
</Setter.Value>
</Setter>
</Style>

​ 请注意NamePART_MessageTextBlock就是用来呈现水印提示消息的,同时加了个触发器,实现这样的功能:如果未输入任何雷人,则显示水印,否则就隐藏水印。

​ 控件使用,上代码:

 <local:WaterMarkTextBox Margin="20,0,0,0" Width="200" Height="50" WaterMark="Please Input your name"/>

上效果:

No3. 附加属性来试试

​ 重写控件看似很完美了,真的是这样吗?

​ 好了,我的需求又来了,现在文本框提示很perfect,开始我的密码框PasswordBox也要搞个水印啊?怎么办?再重写个带水印的密码框?此时有没有做相同事情的感觉?作为合格的码农,我们还是要牢记码农界的警世名言:Don't Repeat Yourself!

​ 此时请回忆下WPF的经典知识点

​ 控件A放到Grid中,A要支持设置行和列,控件B放到Grid中,B也要支持设置行和列。教程中已经告诉我们不要傻不拉几在A和B中都去定义行和列的属性,否则后续C、D......没完没了。

​ 此时就是我们应用附加属性的时候了,在Grid中定义统一的行和列的附加属性,然后附加应用到A、B上就可以了。

​ 反过来看看我们现在的需求,是不是一样的套路?我是不是在个公共的地方定义个水印WaterMark附加属性,然后分别应用到文本框和密码框就可以了?说对了一半,因为我们文本框和密码框老的外表没有显示水印的地方,所以我们同时还要重新定义下他们的新外表。

​ 话不多说,先上附加属性定义的代码:

public class WaterMarkHelper
{
public static string GetWaterMark(DependencyObject obj)
{
return (string)obj.GetValue(WaterMarkProperty);
} public static void SetWaterMark(DependencyObject obj, string value)
{
obj.SetValue(WaterMarkProperty, value);
} public static readonly DependencyProperty WaterMarkProperty =
DependencyProperty.RegisterAttached("WaterMark", typeof(string), typeof(WaterMarkHelper), new PropertyMetadata(null)); }

上TextBox新的样式:

<Style x:Key="TextBoxWithWaterMark" TargetType="{x:Type TextBox}">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
<ScrollViewer x:Name="PART_ContentHost"
Grid.Column="0"
Margin="0"
Padding="{TemplateBinding Padding}"
VerticalAlignment="Stretch"
Background="{x:Null}"
BorderThickness="0"
IsTabStop="False"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<TextBlock x:Name="PART_Message"
Margin="4 0"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="Center"
Foreground="Gray"
Text="{TemplateBinding local:WaterMarkHelper.WaterMark}"
Visibility="Collapsed" />
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
<Setter TargetName="PART_Message" Property="Visibility" Value="Visible" />
</DataTrigger>
</ControlTemplate.Triggers> </ControlTemplate>
</Setter.Value>
</Setter>
</Style>

请和自定义控件中的样式对比下,其实就是PART_Message对应控件的Text绑定的不一样了,这样绑定的是TextBox的附加属性WaterMarkHelper.WaterMark

上应用代码:

 <TextBox Style="{StaticResource TextBoxWithWaterMark}" Margin="20,0,0,0" Width="200" Height="50" local:WaterMarkHelper.WaterMark="Please Input your name"/>

请注意,这样要手动明确应用定义的样式资源!

上效果:

课后作业:请依葫芦画瓢,实现PasswordBox的水印功能

总结

​ 除了这里列举的三种方式,其实还可以通过Behavior行为功能,扩展一个控件的功能,比如著名的拖拽功能!写到这里,我想总结的是:工欲善其事必先利其器

​ 当我们基础扎实之后,我们真的可以跳出栅栏,灵活应用!

源码获取

程序源码

WPF之花式控件功能扩展的更多相关文章

  1. WPF中查找控件的扩展类

    在wpf中查找控件要用到VisualTreeHelper类,但这个类并没有按照名字查找控件的方法,于是搜索网络,整理出下面这个类,感觉用起来很是方便. 贴出来,供大家参考. /// <summa ...

  2. WPF 4 DataGrid 控件(基本功能篇)

    原文:WPF 4 DataGrid 控件(基本功能篇)      提到DataGrid 不管是网页还是应用程序开发都会频繁使用.通过它我们可以灵活的在行与列间显示各种数据.本篇将详细介绍WPF 4 中 ...

  3. DevExpress WPF v19.2图表图形控件功能增强?速速种草

    通过DevExpress WPF Controls,你能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案. 无论是Office办公软件的衍 ...

  4. Windows Community Toolkit 3.0 新功能 在WinForms 和 WPF 使用 UWP 控件

    本文告诉大家一个令人震惊的消息,Windows Community Toolkit 有一个大更新,现在的版本是 3.0 .最大的提升就是 WinForm 和 WPF 程序可以使用部分 UWP 控件. ...

  5. WPF中Ribbon控件的使用

    这篇博客将分享如何在WPF程序中使用Ribbon控件.Ribbon可以很大的提高软件的便捷性. 上面截图使Outlook 2010的界面,在Home标签页中,将所属的Menu都平铺的布局,非常容易的可 ...

  6. 浅尝辄止WPF自定义用户控件(实现颜色调制器)

    主要利用用户控件实现一个自定义的颜色调制控件,实现一个小小的功能,具体实现界面如下. 首先自己新建一个wpf的用户控件类,我就放在我的wpf项目的一个文件夹下面,因为是一个很小的东西,所以就没有用mv ...

  7. WdatePicker 日期控件- 功能及示例

      3. 多语言和自定义皮肤多语言支持 通过lang属性,可以为每个日期控件单独配置语言,当然也可以通过WdatePicker.js配置全局的语言语言列表和语言安装说明详见语言配置 示例3-1 多语言 ...

  8. 深入探讨WPF的ListView控件

    接上一篇博客初步探讨WPF的ListView控件(涉及模板.查找子控件)  我们继续探讨ListView的用法      一.实现排序功能 需求是这样的:假如我们把学生的分数放入ListView,当我 ...

  9. 【转】WPF中PasswordBox控件的Password属性的数据绑定

    英文原文:http://www.wpftutorial.net/PasswordBox.html 中文原文:http://blog.csdn.net/oyi319/article/details/65 ...

随机推荐

  1. 西门子S7200/300/400以太网通讯处理器选型分类

    北京华科远创科技有限研发的远创智控转以太网模块适用于西门子S7-200/S7-300/S7-400.SMART S7-200.西门子数控840D.840DSL.合信.亿维PLC的PPI/MPI/PRO ...

  2. mysql 多字段联合唯一索引

    6个字段组成联合唯一索引 索引名称code_level_metric_type_week_year sql语句联合索引 CREATE UNIQUE INDEX code_level_metric_ty ...

  3. 策略模式干掉if-else,switch

    1.传统if -else 写法 String nodeModelStr = ""; if (nodeType == NodeType.START){ StartModel star ...

  4. 通过 DLPack 构建跨框架深度学习编译器

    通过 DLPack 构建跨框架深度学习编译器 深度学习框架,如Tensorflow, PyTorch, and ApacheMxNet,快速原型化和部署深度学习模型提供了强大的工具箱.不幸的是,易用性 ...

  5. 如何在Python中加速信号处理

    如何在Python中加速信号处理 This post is the eighth installment of the series of articles on the RAPIDS ecosyst ...

  6. XGBoost原理介绍

    XGBoost原理介绍 1. 什么是XGBoost XGBoost是一个开源机器学习项目,实现了GBDT算法,进行了算法和工程上的许多改进,广泛应用在Kaggle竞赛及许多机器学习竞赛中. 说到XGB ...

  7. HLS后端示例

    HLS后端示例 TVM支持带有SDAccel的Xilinx FPGA板.这是有关如何将TVM部署到AWS F1 FPGA实例的文档. 此功能仍处于试验阶段.暂时无法使用SDAccel部署端到端神经网络 ...

  8. Activiti Exploer工作流控制台使用指南!使用Activiti Explorer定义部署执行工作流

    Activiti Explorer简介 Activiti Explorer: Activiti控制台,是一个web应用程序 从Activiti的官方网站下载Activiti的压缩zip文件时,Acti ...

  9. HTML基本标签及语法

    HTML简介 什么是HTML 本文素材来源于黑马程序员Pink老师 HTML 指的是超文本标记语言(Hyper Text Markup Language) ,它是用来描述网页的一种语言. HTML 不 ...

  10. 【转】【NX二次开发】UFUN进度中断,单击停止可中断此操作

    队长的博客: https://www.cnblogs.com/nxopen2018/p/13174207.html 显示此对话框,点击可中断操作: 用到的ufun函数: UF_ABORT_ask_fl ...