WPF 附加属性+控件模板,完成自定义控件。建议观看HandyControl源码

文章目录

  • 相关连接
  • 前言
  • 需要实现的效果
  • 附加属性
    • 添加附加属性,以Test修改FontSize为例
    • 依赖属性使用
      • 触发器使用
      • 直接操控
    • 结论
  • 控件模板,在HandyControl的基础上面进行修改
    • 参考HandyControl的源码
    • 控件模板原型
    • 控件模板
  • 控件模板触发器
    • 完整样式
    • 简单使用
  • 结论

相关连接

WPF控件模板(6)

WPF 附加属性

WPF教程:附加属性

前言

今天说服了领导用WPF开发前端,原因就是开发相对来说比较方便,写小项目就不用前后端分离什么的了。反正就是有个机会写WPF了,真开心。我已经写了一年的Uniapp了

需要实现的效果

就是想写一个简单的变色控件。
在这里插入图片描述

附加属性

如果想知道附加属性,就得先了解依赖属性。详细的可以看我这篇文章

WPF 用户控件依赖属性赋值

添加附加属性,以Test修改FontSize为例

知道了依赖属性之后,我解释一下附加属性是什么意思。附加属性就是为了方便在原有的控件基础上面进行细微的修改。我们先保证编译通过

附加属性的快捷键是propa

简单给TextBox添加一个附加属性

    public partial class TextBlockExtension
    {



        public static int GetTest(DependencyObject obj)
        {
            return (int)obj.GetValue(TestProperty);
        }

        public static void SetTest(DependencyObject obj, int value)
        {
            obj.SetValue(TestProperty, value);
        }

        // Using a DependencyProperty as the backing store for Test.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TestProperty =
            DependencyProperty.RegisterAttached("Test", typeof(int), typeof(TextBox), new PropertyMetadata(10));
        
        
    }

这样我们就能编译通过了。

<TextBlock Text="用户"  wpfEx:TextBlockExtension.Test="2"/>

在这里插入图片描述

依赖属性使用

依赖属性有两种使用方法

触发器使用

样式定义

    <!--一个简单的FontSize修改-->
    <Style x:Key="UserSelection"
           TargetType="TextBlock">
        <!--因为Triggers只有等于判断,所以这里简单写了一下-->
        <Style.Triggers>
            <Trigger Property="wpfEx:TextBlockExtension.Test"
                     Value="10">
                <Setter Property="FontSize"
                        Value="10" />
            </Trigger>
            <Trigger Property="wpfEx:TextBlockExtension.Test"
                     Value="20">
                <Setter Property="FontSize"
                        Value="20" />
            </Trigger>
        </Style.Triggers>
    </Style>

简单使用

 <TextBlock Text="用户"
            wpfEx:TextBlockExtension.Test="10" Style="{StaticResource UserSelection}">
     
 </TextBlock>
 <TextBlock Text="用户"
            wpfEx:TextBlockExtension.Test="20"
            Style="{StaticResource UserSelection}">
 </TextBlock>

在这里插入图片描述

直接操控

附加属性修改

//如果想直接操控元素,得在PropertyMetadata进行操控。记得设置初始值
public static readonly DependencyProperty TestProperty =
    DependencyProperty.RegisterAttached("Test", typeof(int), typeof(TextBox), new PropertyMetadata(10,(s, e) =>
    {
        //s是控件本身,
        var mdp = s as TextBlock;
        //如果控件是该元素的父组件,类似于Grid和DockPanel,就使用Parent来寻找,这里不展开
        //var mdpParent = (s as FrameworkElement).Parent as TextBlock;
        if (mdp != null && e.NewValue != null)
        {
            mdp.FontSize = (int)e.NewValue;
        }
    }));
<!--如果想要预览生效需要重新编译一下-->
<TextBlock Text="用户"
           wpfEx:TextBlockExtension.Test="15">

</TextBlock>
<TextBlock Text="用户"
           wpfEx:TextBlockExtension.Test="20">
</TextBlock>
<!--因为我们设置了默认值为10,所以这里是10-->
<TextBlock Text="用户">
</TextBlock>
<!--优先级还是依赖属性高,所以这里是30而不是默认值10-->
<TextBlock Text="用户" FontSize="30">
</TextBlock>

在这里插入图片描述

结论

附加属性和依赖属性差不多,就是声明麻烦一点。因为Get,Set是需要额外写的。

控件模板,在HandyControl的基础上面进行修改

控件模板一般用于按钮,我们只要会按钮的控件模板就可以了。

WPF控件模板(6)

参考HandyControl的源码

HandyControl 页面

HandyControl的Button有IconButton的样式源码。看一下还是挺有收获的。

在这里插入图片描述
参考样式代码

 <Style x:Key="ButtonDashedBaseStyle" BasedOn="{StaticResource ButtonBaseStyle}" TargetType="Button">
     <Setter Property="Background" Value="Transparent"/>
     <Setter Property="Template">
         <Setter.Value>
             <ControlTemplate TargetType="Button">
                 <hc:DashedBorder BorderDashArray="3,2" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="Transparent" CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}">
                     <StackPanel Orientation="Horizontal" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}">
                         <Path x:Name="PathMain" Width="{TemplateBinding hc:IconElement.Width}" Height="{TemplateBinding hc:IconElement.Height}" Fill="{TemplateBinding Foreground}" SnapsToDevicePixels="True" Stretch="Uniform" Data="{TemplateBinding hc:IconElement.Geometry}"/>
                         <ContentPresenter x:Name="ContentPresenterMain" RecognizesAccessKey="True" VerticalAlignment="Center" Margin="6,0,0,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                     </StackPanel>
                 </hc:DashedBorder>
                 <ControlTemplate.Triggers>
                     <Trigger Property="Content" Value="{x:Null}">
                         <Setter Property="Visibility" Value="Collapsed" TargetName="ContentPresenterMain"/>
                     </Trigger>
                     <Trigger Property="hc:IconElement.Geometry" Value="{x:Null}">
                         <Setter Property="Visibility" Value="Collapsed" TargetName="PathMain"/>
                         <Setter Property="Margin" Value="0" TargetName="ContentPresenterMain"/>
                     </Trigger>
                 </ControlTemplate.Triggers>
             </ControlTemplate>
         </Setter.Value>
     </Setter>
 </Style>

在这里插入图片描述

控件模板原型

我们想写一个控件模板,如果不是很熟练,我们就先把控件模板的原型写出来,这样更利于理解。

 <DockPanel>
     <!--这里仿照HandyControl,使用Gemotery。IconPacks怎么转Gemotery可以看我的文章-->


     <Border DockPanel.Dock="Top"
             Width="50"
             Height="50"
             CornerRadius="25"
             Background="DeepSkyBlue">
         <Path Data="{wpfEx:MaterialGeometry Kind=BellRing}"
               HorizontalAlignment="Stretch"
               VerticalAlignment="Stretch"
               SnapsToDevicePixels="True"
               Stretch="Uniform"
               Width="25"
               Height="25"
               Fill="White" />
     </Border>

     <TextBlock Text="TIM登录"
                HorizontalAlignment="Center" />
 </DockPanel>

在这里插入图片描述

控件模板

<Style x:Key="UserSelection"
       TargetType="RadioButton"
       BasedOn="{StaticResource {x:Type RadioButton}}">
    <Setter Property="Template">
        <Setter.Value>
            <!--先按照之前的样式粘贴一下-->
            <ControlTemplate TargetType="RadioButton">
                <DockPanel>
                    <Border DockPanel.Dock="Top"
                            Width="50"
                            Height="50"
                            CornerRadius="25"
                            Background="DeepSkyBlue">
                        <Path Data="{wpfEx:MaterialGeometry Kind=BellRing}"
                              HorizontalAlignment="Stretch"
                              VerticalAlignment="Stretch"
                              SnapsToDevicePixels="True"
                              Stretch="Uniform"
                              Width="25"
                              Height="25"
                              Fill="White" />
                    </Border>
                    <ContentPresenter x:Name="ContentPresenterMain"
                                      RecognizesAccessKey="True"
                                      VerticalAlignment="Center"
                                      Margin="6,0,0,0"
                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

在这里插入图片描述

然后里面能绑定的就绑定。也是照着HandyControl改的。注意这里的Banding用的是TemplateBinding

在这里插入图片描述

修改好的效果

<!--一个简单的FontSize修改-->
<Style x:Key="UserSelection"
       TargetType="RadioButton"
       BasedOn="{StaticResource {x:Type RadioButton}}">
    <Setter Property="Template">
        <Setter.Value>
            <!--先按照之前的样式粘贴一下-->
            <ControlTemplate TargetType="RadioButton">
                <DockPanel>
                    <Border DockPanel.Dock="Top"
                            Width="{TemplateBinding hc:IconElement.Width}"
                            Height="{TemplateBinding hc:IconElement.Height}"
                            CornerRadius="25"
                            Background="{TemplateBinding Foreground}">
                        <Path Data="{TemplateBinding hc:IconElement.Geometry}"
                              HorizontalAlignment="Stretch"
                              VerticalAlignment="Stretch"
                              SnapsToDevicePixels="True"
                              Stretch="Uniform"
                              Width="25"
                              Height="25"
                              Fill="{TemplateBinding Background}" />
                    </Border>
                    <ContentPresenter x:Name="ContentPresenterMain"
                                      RecognizesAccessKey="True"
                                      VerticalAlignment="Center"
                                        
                                      Margin="6,0,0,0"
                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

简单使用

<RadioButton Content="TIM登录"
             GroupName="UserSelect"
             Style="{StaticResource UserSelection}"
             Foreground="DeepSkyBlue"
             Background="White"
             hc:IconElement.Geometry="{wpfEx:MaterialGeometry Kind=AbTesting}" />

在这里插入图片描述

控件模板触发器

完整样式

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:wpfEx="clr-namespace:BluetoothWPF.WpfExtensions"
                    xmlns:hc="https://handyorg.github.io/handycontrol"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <!--一个简单的FontSize修改-->
    <Style x:Key="UserSelection"
           TargetType="RadioButton"
           BasedOn="{StaticResource {x:Type RadioButton}}">
        <Setter Property="Foreground"
                Value="Gray" />
        <Setter Property="Template">
            <Setter.Value>
                <!--先按照之前的样式粘贴一下-->
                <ControlTemplate TargetType="RadioButton">
                    <DockPanel>
                        <Border DockPanel.Dock="Top"
                                Width="70"
                                Height="70"
                                CornerRadius="35"
                                x:Name="Background">
                            <Path Data="{TemplateBinding hc:IconElement.Geometry}"
                                  x:Name="Icon"
                                  HorizontalAlignment="Stretch"
                                  VerticalAlignment="Stretch"
                                  SnapsToDevicePixels="True"
                                  Stretch="Uniform"
                                  Width="35"
                                  Height="35"
                                  Fill="Gray" />
                        </Border>
                        <ContentPresenter x:Name="ContentPresenterMain"
                                          RecognizesAccessKey="True"
                                          VerticalAlignment="Center"
                                          HorizontalAlignment="Center"
                                          Margin="6,0,0,0"
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                    </DockPanel>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver"
                                 Value="True">
                            <Setter TargetName="Background"
                                    Property="Background"
                                    Value="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}" />
                            <Setter TargetName="Icon"
                                    Property="Fill"
                                    Value="White" />
                        </Trigger>
                        <Trigger Property="IsFocused"
                                 Value="True">
                            <Setter TargetName="Background"
                                    Property="Background"
                                    Value="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}" />
                            <Setter TargetName="Icon"
                                    Property="Fill"
                                    Value="White" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="RadioButton"
           x:Key="UserSelectioin_Admin"
           BasedOn="{StaticResource UserSelection}">
        <Setter Property="HorizontalAlignment"
                Value="Right" />
        <Setter Property="Margin"
                Value="0 0 10 0" />
        <Setter Property="Background"
                Value="DeepSkyBlue" />
        <Setter Property="hc:IconElement.Geometry"
                Value="{wpfEx:MaterialGeometry Kind=AccountLock}" />
        <Setter Property="Content"
                Value="管理员登录" />

    </Style>
    <Style TargetType="RadioButton"
           x:Key="UserSelectioin_User"
           BasedOn="{StaticResource UserSelection}">
        <Setter Property="HorizontalAlignment"
                Value="Left" />
        <Setter Property="Margin"
                Value="10 0 0 0" />
        <Setter Property="Background"
                Value="Green" />
        <Setter Property="hc:IconElement.Geometry"
                Value="{wpfEx:MaterialGeometry Kind=Account}" />
        <Setter Property="Content"
                Value="用户" />
    </Style>
</ResourceDictionary>

简单使用

<RadioButton Style="{StaticResource UserSelectioin_Admin}" />
<RadioButton Style="{StaticResource UserSelectioin_User}" />

在这里插入图片描述
在这里插入图片描述

结论

HandyControl的源码看了真的是打开眼界,但是WPF的Xaml有一个无法在内部简单计算的问题。比如我想Witdh=Height = CornerRadius*2。我可能就要写个触发器了。我后面回去测试一下有没有方法可以在Xaml里面简单计算的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/412401.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

光学3D表面轮廓仪微纳米三维形貌一键测量

光学3D表面轮廓仪(白光干涉仪)利用白光干涉原理&#xff0c;以0.1nm分辨率精准捕捉物体的表面细节&#xff0c;实现三维显微成像测量&#xff0c;被广泛应用于材料学领域的研究和应用。 了解工作原理与技术 材料学领域中的光学3D表面轮廓仪&#xff0c;也被称为白光干涉仪&am…

低价对品牌渠道的危害

品牌价值的体现主要在价格&#xff0c;比如要与竞品体现差异&#xff0c;除了产品功能上有做出差异&#xff0c;价格上也需要设置不同的阶梯&#xff0c;但如果经销商不遵守这个体系&#xff0c;或者非授权店铺随意低价&#xff0c;对于品牌来说都是非常不好的事情&#xff0c;…

Django后台管理(二)

一、自定义注册管理类介绍 官网:Django 管理站点 | Django 文档 | Django 注册模型除了使用 Django 默认的管理类admin,也可以自定义,比如: class StudentAdmin(admin.ModelAdmin):pass admin.site.register(Student, StudentAdmin)ModelAdmin 类是管理界面中模型的表示。…

微信小程序 wxs内联与外联的写法

内联写法 <!-- 内联wxs --> <view>大写字母{{m1.toUpper("xmly")}}</view> <wxs module"m1">module.exports.toUpperfunction(str){return str.toUpperCase()} </wxs> 外联写法 新建一个wxs文件 写一个函数&#xff0c;将…

架构(十五)Java字节码增强

一、引言 一般如果需要做增强类的架构工具会使用SpringBoot提供的切面&#xff0c;但是这逃不开两个问题&#xff1a;1、使用方需要加注解代码&#xff1b;2、版本更新导致的发布。 所以java还提供了字节码层面的增强方案&#xff0c;对使用的系统是无感的。 二、字节码增强选…

BLEU: a Method for Automatic Evaluation of Machine Translation

文章目录 BLEU: a Method for Automatic Evaluation of Machine Translation背景和意义技术原理考虑 n n n - gram中 n 1 n1 n1 的情况考虑 n n n - gram中 n > 1 n\gt 1 n>1 的情况考虑在文本中的评估初步实验评估和结论统一不同 n n n 值下的评估数值考虑句子长度…

Ubuntu上Jenkins自动化部署Gitee上SpringBoot项目

文章目录 安装安装JDK安装Maven安装GitNodeJS安装&#xff08;可选&#xff09;安装Jenkins 配置Jenkins为Jenkins更换插件源设置jenkins时区安装插件全局工具配置添加Gitee凭证Gitee项目配置 部署后端1.新建任务2.配置源码管理3.构建触发器4.到Gitee中添加WebHook5.构建环境6.…

C++——基础语法(3):内联函数、auto关键字、基于范围的for循环、空指针nullptr

6. 内联函数 在函数前加入inline修饰即可将函数变为内联函数。所谓内联函数&#xff0c;就是在编译时C编译器会将函数体在调用内联函数的地方展开&#xff0c;从而省去了调用函数的栈帧开销&#xff0c;提高程序运行效率。 inline int Add(int a, int b) {return a b; } int …

十一、计算机视觉-膨胀操作

文章目录 前言一、什么是膨胀二、膨胀操作的实现1.引入库 三、膨胀的原理 前言 上节我们学习了腐蚀操作&#xff0c;本节我们讲一下膨胀操作&#xff0c;膨胀和腐蚀实际上是相反的操作。上节我们把云峰这2个字周围没用的像素去掉了&#xff0c;但是云峰这2个字也变细了&#x…

Protocol Buffer-nanopb介绍

文章目录 一、需求二、环境三、相关概念3.1 protocol buffer介绍3.2 nanopb&#xff08;支持C语言&#xff09;3.3 proto文件 四、proto基本语法4.1 proto文件的定义4.2 字段规则4.3 字段类型4.4 字段编号4.5 proto语法4.6 进阶语法4.6.1 message嵌套4.6.2 enum关键字4.6.3 one…

【Flink精讲】Flink状态及Checkpoint调优

RocksDB大状态调优 RocksDB 是基于 LSM Tree 实现的&#xff08;类似 HBase&#xff09; &#xff0c;写数据都是先缓存到内存中&#xff0c; 所以 RocksDB 的写请求效率比较高。 RocksDB 使用内存结合磁盘的方式来存储数据&#xff0c;每 次获取数据时&#xff0c;先从内存中 …

什么是高可用架构

一、什么是高可用 在运维中&#xff0c;经常听到高可用&#xff0c;那么什么是高可用架构呢&#xff1f;通俗点讲&#xff0c;高可用就是在服务故障&#xff0c;节点宕机的情况下&#xff0c;业务能够保证不中断&#xff0c;服务正常运行。 举个例子&#xff0c;支付宝&#…

GS069——直流有刷电机调速电路 通过外接电阻网络,改变与之相接的 VMOS 管的输出,达到控制电动工具 转速的作用。 功耗小,电源电压范围宽。

GS069电动工具直流调速电路是CMOS专用集成电路&#xff0c;具有电源电压范 围宽、功耗小、抗干扰能力强等特点。通过外接电阻网络&#xff0c;改变与之相接 的VMOS 管的输出&#xff0c;达到控制电动工具转速的作用。该电路输出幅值宽&#xff0c; 频率变化小&#xff0c;占空比…

vue ts html 中如何遍历 Enum 类型构建页面结构

vue ts html 中如何遍历 Enum 类型构建页面结构 一、需求 定义了一个 Enum 用来标记菜单类型&#xff1a; enum EnumMenuType {目录 1,菜单,按钮,外链 }你得 Enum 知道它的序号是随第一个定义的值自动增长的 现在想在 ElementUI 界面的 radio-group 中遍历它&#xff0c;…

聚集高速托盘类四向穿梭车ASRV|一车跑全仓可获得10000个货位的HEGERLS智能搬运机器人

随着国内外制造业加速转型升级&#xff0c;越来越多的企业需要进行物流智能化升级&#xff0c;但是往往受到仓库面积、高度、形状等现实条件的限制&#xff0c;以及市场不确定性因素的影响。因此&#xff0c;相对于投资传统的自动化立体库&#xff0c;企业更倾向于选择智能化、…

HarmonyOS—低代码开发Demo示例

接下来为大家展示一个低代码开发的JS工程的Demo示例&#xff0c;使用低代码开发如下华为手机介绍列表的HarmonyOS应用/服务示例。 1.删除模板页面中的控件后&#xff0c;选中组件栏中的List组件&#xff0c;将其拖至中央画布区域&#xff0c;松开鼠标&#xff0c;实现一个List组…

[设计模式Java实现附plantuml源码~行为型] 撤销功能的实现——备忘录模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

formality:set_constant应用

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 往期文章链接: formality:形式验证流程 scan mode func的功能检查需要把scan mode设置成0。

python Matplotlib Tkinter-->导出pdf报表

环境 python:python-3.12.0-amd64 包: matplotlib 3.8.2 reportlab 4.0.9 import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import tkinter as tk import tkinter.messagebox as messagebox impor…