文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

WPF开发的控件功能扩展

2023-06-20 16:20

关注

这篇文章主要讲解了“WPF开发的控件功能扩展”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“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>

上外表:

WPF开发的控件功能扩展

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"/>

上效果:

WPF开发的控件功能扩展

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"/>

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

上效果:

WPF开发的控件功能扩展 

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

总结

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

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

感谢各位的阅读,以上就是“WPF开发的控件功能扩展”的内容了,经过本文的学习后,相信大家对WPF开发的控件功能扩展这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯