iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >WPF开发技巧之花式控件功能扩展详解
  • 534
分享到

WPF开发技巧之花式控件功能扩展详解

2024-04-02 19:04:59 534人浏览 泡泡鱼
摘要

目录No1. 自定义控件模板No2. 重写控件No3. 附加属性来试试总结文章默认你已经入门WPF了 ​ WPF日常开发,经常遇到默认的控件功能不满足需求,怎么办? No

文章默认你已经入门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花式控件功能扩展内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: WPF开发技巧之花式控件功能扩展详解

本文链接: https://www.lsjlt.com/news/130705.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • WPF开发技巧之花式控件功能扩展详解
    目录No1. 自定义控件模板No2. 重写控件No3. 附加属性来试试总结文章默认你已经入门WPF了 ​ WPF日常开发,经常遇到默认的控件功能不满足需求,怎么办? No...
    99+
    2024-04-02
  • WPF开发的控件功能扩展
    这篇文章主要讲解了“WPF开发的控件功能扩展”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“WPF开发的控件功能扩展”吧!目录No1. 自定义控件模板No2. 重写控件No3. 附加属性来试试...
    99+
    2023-06-20
  • 移动web开发技能之touch事件详解
    目录概述touch事件touch事件分类touch事件对象移动web单击事件iOS单击延迟“单击穿透”问题概述 单击事件是任何一个前端页面中最常用的交互行为之...
    99+
    2024-04-02
  • 详解使用PHP开发直播功能的实用技巧
    随着互联网的不断发展,直播功能也越来越受到人们的关注和青睐。在这样一个直播风潮的时代,需要一款稳定可靠的直播平台。而PHP作为一种强大的服务器端开发语言,可以用于创建高度交互性的应用程序,能够为直播平台的开发提供利器,本文就为大家详细介绍使...
    99+
    2023-05-22
    直播 技巧 PHP
  • C++ 函数库详解:系统功能外延开发技巧与最佳实践
    c++++ 函数库提供系统功能扩展,提升代码可重用性、可维护性和效率。优点包括:可重用性:节约开发时间。可维护性:集中代码,易于更新。效率:经过优化,提供最佳性能。标准化:提供一致接口。...
    99+
    2024-05-03
    c++ 函数库 标准库
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作