WPF开发技巧之花式控件功能扩展详解
文章默认你已经入门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>
请注意Name为PART_Message的TextBlock就是用来呈现水印提示消息的,同时加了个触发器,实现这样的功能:如果未输入任何内容,则显示水印,否则就隐藏水印。
控件使用,上代码:
<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日常开发之花式控件功能扩展的文章就介绍到这了,更多相关WPF花式控件功能扩展内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
- 这篇文章主要给大家介绍了关于C#创建自定义控件及添加自定义属性和事件使用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-06-25
c# WPF中通过双击编辑DataGrid中Cell的示例(附源码)
这篇文章主要介绍了c# WPF中通过双击编辑DataGrid中Cell的示例(附源码),帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下...2021-03-03- 这篇文章主要介绍了C#实现跨线程操作控件方法,主要采用异步访问方式实现,需要的朋友可以参考下...2020-06-25
- 最近在网上看到了新版的360安全卫士,感觉界面还不错,于是用WPF制作了一个,时间有限,一些具体的控件没有制作,用图片代替了。感兴趣的朋友一起跟着小编学习WPF实现类似360安全卫士界面的程序源码分享...2020-06-25
- 这篇文章主要介绍了C# 如何设置label(标签)控件的背景颜色为透明,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2020-12-08
- 本篇文章是对C#中自定义控件的制作与使用实例进行了详细的分析介绍,需要的朋友参考下...2020-06-25
- 这篇文章主要为大家详细介绍了Bootstrap树形控件使用方法,感兴趣的小伙伴们可以参考一下...2016-01-29
学习使用bootstarp基本控件(table、form、button)
这篇文章主要教会大家学习使用bootstarp基本控件,如table、form、button控件,感兴趣的小伙伴们可以参考一下...2016-04-16- 这篇文章主要介绍了C#实现根据指定容器和控件名字获得控件的方法,其中包括了遍历与递归的应用,需要的朋友可以参考下...2020-06-25
Repeater事件OnItemCommand取得行内控件的方法
这篇文章主要介绍了Repeater事件OnItemCommand取得行内控件的方法,有需要的朋友可以参考一下...2021-09-22- 这篇文章主要介绍了C#多线程与跨线程访问界面控件的方法,实例分析了C#多线程与跨线程访问空间的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 这篇文章主要为大家详细介绍了WPF仿三星手机充电界面实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
- activex控件以前也叫做ole控件,它是微软ie支持的一种软件组件或对象,可以将其插入到web页面中,实现在浏览器端执行动态程序功能,以增强浏览器端的动态处理能力。通常activex控件都是用c++或vb语言开发,本文介绍另一种方式,使用c#语言开发activex控件。...2020-06-25
- 这篇文章主要介绍了C#自定义控件添加右键菜单的方法,本文用到control控件,专门自定义右键菜单,下面小编给大家整理下,有需要的小伙伴可以来参考下...2020-06-25
- 这篇文章主要介绍了C# WPF 通过委托实现多窗口间的传值的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
- 下面小编就为大家分享一篇基于C#调用OCX控件的常用方法推荐,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-06-25
C++ Custom Control控件向父窗体发送对应的消息
这篇文章主要介绍了C++ Custom Control控件向父窗体发送对应的消息的相关资料,需要的朋友可以参考下...2020-04-25- 这篇文章主要为大家详细介绍了javascript特殊日历控件的使用方法,展示了javascript日历控件实现效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-03-09
- 这篇文章主要为大家详细介绍了利用jmSlip编写移动端顶部日历选择组件的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-10-25
- 这篇文章主要为大家详细介绍了WPF TextBox实现按字节长度限制输入功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25