WPF中如何自定义控件

WPF自定义控件简化版:账户菜单按钮(AccountButton)

我们以**“账户菜单按钮”为例,用更清晰的架构实现一个支持标题显示、渐变背景、选中状态高亮**的自定义控件。以下是分步拆解:


一、控件核心功能

我们要做一个类似这样的控件:

  • 外观:一个圆形/圆角的小按钮,中间显示标题(如账户首字母)。
  • 背景:支持自定义渐变颜色(从颜色A到颜色B)。
  • 选中状态:左侧显示一条高亮竖线(选中时可见,未选中时隐藏)。

二、控件架构设计(分3步)

步骤1:创建UserControl(控件容器)

WPF中自定义控件最常用的方式是继承UserControl(用户控件),它本质是一个可复用的UI容器,包含自己的XAML布局和后台代码。

步骤2:定义依赖属性(暴露控件属性)

为了让控件能被外部配置(如修改标题、颜色、选中状态),需要将这些属性注册为依赖属性(DependencyProperty)。依赖属性的优势是支持数据绑定、样式设置和动态更新。

步骤3:设计XAML布局(可视化界面)

在XAML中定义控件的UI结构,将依赖属性绑定到具体的UI元素(如文本、背景颜色、可见性)。


三、完整代码实现(简化版)

1. 新建UserControl:AccountButton.xaml

XAML中定义控件的布局,核心是一个Button,内部包含两个Border(高亮条和背景块)。

<UserControl x:Class="MyApp.Controls.AccountButton"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Name="Root"  <!-- 给控件起别名,方便绑定 -->Width="30" Height="30">  <!-- 固定控件大小 --><!-- 根元素是一个按钮 --><Button Style="{StaticResource BaseButtonStyle}">  <!-- 假设外部有基础样式 --><Grid><!-- 选中状态高亮条(左侧竖线) --><Border x:Name="ActiveIndicator"HorizontalAlignment="Left"Width="3"Background="#FF0078D7"  <!-- 蓝色高亮 -->Visibility="Collapsed"  <!-- 默认隐藏 -->CornerRadius="0 2 2 0"/>  <!-- 右侧圆角 --><!-- 背景块(显示渐变和标题) --><Border x:Name="ContentBorder"Width="25" Height="25"HorizontalAlignment="Center"VerticalAlignment="Center"CornerRadius="3">  <!-- 圆角 --><!-- 渐变背景 --><Border.Background><LinearGradientBrush StartPoint="0,0" EndPoint="1,1"><!-- 起始色绑定控件的GradientStart属性 --><GradientStop Color="{Binding GradientStart, ElementName=Root}" Offset="0"/><!-- 结束色绑定控件的GradientEnd属性 --><GradientStop Color="{Binding GradientEnd, ElementName=Root}" Offset="1"/></LinearGradientBrush></Border.Background><!-- 标题文本(绑定控件的Title属性) --><TextBlock Text="{Binding Title, ElementName=Root}"VerticalAlignment="Center"HorizontalAlignment="Center"Foreground="White"FontWeight="Bold"/></Border></Grid></Button>
</UserControl>
2. 后台代码:AccountButton.xaml.cs

定义依赖属性,并处理选中状态的逻辑(例如:选中时显示高亮条)。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;namespace MyApp.Controls
{public partial class AccountButton : UserControl{public AccountButton(){InitializeComponent();}// ----------------------//  依赖属性定义(共3个)// ----------------------// 1. 标题(如账户首字母)public string Title{get => (string)GetValue(TitleProperty);set => SetValue(TitleProperty, value);}public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title",              // 属性名(必须与包装器一致)typeof(string),       // 属性类型typeof(AccountButton) // 控件类型(当前类));// 2. 渐变起始色public Color GradientStart{get => (Color)GetValue(GradientStartProperty);set => SetValue(GradientStartProperty, value);}public static readonly DependencyProperty GradientStartProperty = DependencyProperty.Register("GradientStart", typeof(Color), typeof(AccountButton));// 3. 渐变结束色public Color GradientEnd{get => (Color)GetValue(GradientEndProperty);set => SetValue(GradientEndProperty, value);}public static readonly DependencyProperty GradientEndProperty = DependencyProperty.Register("GradientEnd", typeof(Color), typeof(AccountButton));// 4. 选中状态(新增:控制高亮条可见性)public bool IsActive{get => (bool)GetValue(IsActiveProperty);set => SetValue(IsActiveProperty, value);}public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register("IsActive", typeof(bool), typeof(AccountButton),new PropertyMetadata(false, OnIsActiveChanged) // 添加回调:状态变化时触发);// 当IsActive属性变化时,更新高亮条可见性private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var button = d as AccountButton;if (button != null){// 根据IsActive的值显示/隐藏高亮条button.ActiveIndicator.Visibility = (bool)e.NewValue ? Visibility.Visible : Visibility.Collapsed;}}}
}

四、代码关键点解释(超简单版)

1. 依赖属性的作用
  • 外部可以通过TitleGradientStart等属性直接配置控件(类似原生控件的WidthHeight)。
  • 示例:在主窗口中使用控件时,可以这样写:
    <controls:AccountButton Title="A" GradientStart="#FF0078D7" GradientEnd="#FF00B4D8" IsActive="True"/>
    
2. 选中状态的自动更新

通过IsActivePropertyPropertyMetadata添加了OnIsActiveChanged回调函数。当IsActive的值变化时(如从False变为True),会自动触发这个函数,更新高亮条的可见性。

3. XAML绑定的逻辑
  • ElementName=RootRoot是UserControl的x:Name,通过它可以直接访问控件本身的属性(如GradientStart)。
  • 渐变颜色直接绑定到GradientStartGradientEnd,当这两个属性的值变化时,背景会自动更新。

五、最终效果

  • 未选中时:显示渐变背景和标题,左侧高亮条隐藏。
  • 选中时:左侧高亮条显示(颜色固定为蓝色),其他部分不变。

通过这种架构,你可以快速扩展控件功能(如添加点击事件、修改高亮条颜色等),核心逻辑清晰易理解!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Deepseek+Xmind:秒速生成思维导图与流程图

deepseekxmind&#xff0c;快速生成思维导图和流程图 文章目录 思维导图deepseek笔记本 txt文件xmind 流程图deepseekdraw.io 思维导图 deepseek 笔记本 txt文件 将deep seek的东西复制到文本文件中&#xff0c;然后将txt文件拓展名改成md xmind 新建思维导图----左上角三…

基于javaweb的SpringBoot爱游旅行平台设计和实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…

服务器机架的功能和重要性

服务器已经成为各个行业必不可少的网络设备&#xff0c;而服务器机架则是数据中心和IT基础设施中不可或缺的重要组成部分&#xff0c;服务器机架能够为服务器和其他网络设备提供物理支撑&#xff0c;同时还可以提供设备维护和管理等多种功能&#xff0c;本文就来介绍一下服务器…

游戏引擎学习第277天:稀疏实体系统

回顾并为今天定下基调 上次我们结束的时候&#xff0c;基本上已经控制住了跳跃的部分&#xff0c;达到了我想要的效果&#xff0c;现在我们主要是在等待一些新的艺术资源。因此&#xff0c;等新艺术资源到位后&#xff0c;我们可能会重新处理跳跃的部分&#xff0c;因为现在的…

阿克曼-幻宇机器人系列教程1- 实现上位机与下位机交互的两种方式

1. 电脑与机器人通过SSH命令连接 1.1 将机器人上电 目的&#xff1a;将机器人变成热点 目标&#xff1a;将电脑连接机器人网络 热点名称&#xff1a;Huanyu-111 密码&#xff1a;12345678 1.2 完成电脑与机器人之间的连接 实现&#xff1a;在电脑终端中执行命令通过SSH登录…

Rust 中的 Pin 和 Unpin:内存安全与异步编程的守护者

在 Rust 的世界里&#xff0c;Pin 和 Unpin 是两个看似不起眼、实则至关重要的概念。它们在内存安全和异步编程中扮演着关键角色&#xff0c;是 Rust 开发者必须掌握的知识。今天&#xff0c;就让我们深入探讨这两个概念&#xff0c;看看它们是如何在 Rust 的生态系统中发挥作用…

如何界定合法收集数据?

首席数据官高鹏律师团队 在当今数字化时代&#xff0c;数据的价值日益凸显&#xff0c;而合法收集数据成为了企业、机构以及各类组织必须严守的关键准则。作为律师&#xff0c;深入理解并准确界定合法收集数据的范畴&#xff0c;对于保障各方权益、维护法律秩序至关重要。 一…

自动驾驶的“眼睛”:用Python构建智能障碍物检测系统

自动驾驶的“眼睛”:用Python构建智能障碍物检测系统 在自动驾驶技术日益成熟的今天,障碍物检测系统成了汽车智能化不可或缺的部分。无论是高速公路上的突发状况,还是城市街道中的行人与车辆,准确识别障碍物并及时反应,是保证行车安全的关键。 那么,我们如何用Python构…

19.Excel数据透视表:第2部分数据透视计算

一 日期组合 不想看具体是哪一天的收入&#xff0c;想看每个月的收入是多少&#xff0c;要对日期进行组合。 光标选中日期字段下的数据&#xff0c; 右键。 补充&#xff1a;第2种方法。 补充&#xff1a;可以同时选择多个。 下面这个是错误的。 源数据里面有不同的年份&#x…

Eclipse 插件开发 6 右键菜单

Eclipse 插件开发 6 右键菜单 1 plugin.xml2 SampleHandler.java3 Activator.java 1 plugin.xml <?xml version"1.0" encoding"UTF-8"?> <?eclipse version"3.4"?> <plugin><!-- 定义命令 --><extension point&…

用vite脚手架建立 前端工程

​ 参考 开始 | Vite 官方中文文档 脚本 chcp 65001 echo 建立vite工程 set PRO_NAMEmy-vue-app call npm create vitelatest %PRO_NAME% --template vue cd ./%PRO_NAME%set NOW_PATH%cd% echo now_path %NOW_PATH% echo 点击回车启动vite工程&#xff0c;请访问ht…

ESP32C3连接wifi

文章目录 &#x1f527; 一、ESP32-C3 连接 Wi-Fi 的基本原理&#xff08;STA 模式&#xff09;✅ 二、完整代码 注释讲解&#xff08;适配 ESP32-C3&#xff09;&#x1f4cc; 三、几个关键点解释&#x1f51a; 四、小结 &#x1f527; 一、ESP32-C3 连接 Wi-Fi 的基本原理&a…

LangSmith 基本使用教程

LangSmith 是一个强大的工具&#xff0c;可以帮助开发者追踪、监控和分析语言模型应用程序的性能。下面我将介绍两种基本的追踪方式&#xff1a;追踪 OpenAI 调用和追踪整个应用程序。 1. 追踪 OpenAI 调用 (Trace OpenAI calls) 这种方法主要用于追踪对 OpenAI API 的调用&a…

Python基础学习-Day23

目录 基础概念转换器&#xff08;transformer&#xff09;估计器&#xff08;estimator&#xff09;管道&#xff08;pipeline&#xff09; 实例pipeline 基础概念 pipeline在机器学习领域可以翻译为“管道”&#xff0c;也可以翻译为“流水线”&#xff0c;是机器学习中一个重…

相对论速度叠加公式与双曲正切

复习下相对论速度叠加公式吧&#xff0c;物理&#xff0c;是不是很多人都忘了呀。假设速度为 u , v u,v u,v&#xff0c;那么叠加后的速度 w w w为&#xff1a; w u v 1 u v / c 2 w\frac{uv}{1uv/c^2} w1uv/c2uv​   这个公式告诉我们&#xff0c;在一个速度为2/3光速的…

【前缀和】和为 K 的子数组(medium)

【前缀和】和为 K 的子数组 题目描述算法原理和细节问题代码 题目描述 和为 K 的子数组 给定一个整数数组和一个整数 k &#xff0c;请找到该数组中和为 k 的连续子数组的个数。 示例 1&#xff1a; 输入:nums [1,1,1], k 2 输出: 2 解释: 此题 [1,1] 与 [1,1] 为两种不同的…

在Ubuntu服务器上部署Label Studio

一、拉取镜像 docker pull heartexlabs/label-studio:latest 二、启动容器 &#xff08;回到用户目录&#xff0c;例&#xff1a;输入pwd&#xff0c;显示 /home/<user>&#xff09; docker run -d --name label-studio -it -p 8081:8080 -v $(pwd)/mydata:/label-st…

MySQL 从入门到精通(三):日志管理详解 —— 从排错到恢复的核心利器

在 MySQL 数据库的日常运维中&#xff0c;日志是定位问题、优化性能、数据恢复的核心工具。无论是排查服务器启动异常&#xff0c;还是分析慢查询瓶颈&#xff0c;亦或是通过二进制日志恢复误删数据&#xff0c;日志都扮演着 “数据库黑匣子” 的角色。本文将深入解析 MySQL 的…

内存中的“BANK”

一、BANK的定义与物理结构 基本概念 BANK&#xff08;存储体&#xff09; 是内存芯片内部的一个逻辑或物理分区&#xff0c;每个BANK由存储单元阵列、地址解码电路和缓冲器组成&#xff0c;用于分块管理内存操作。 作用&#xff1a;通过并行操作减少访问冲突&#xff0c;提升内…

机器学习——聚类算法练习题

一、 随机创建不同二维数据集作为训练集 &#xff0c;并结合k-means算法将其聚类 &#xff0c;你可以尝试分别聚类不同数量的簇 &#xff0c;并观察聚类 效果&#xff1a; 聚类参数n_cluster传值不同 &#xff0c;得到的聚类结果不同 代码展示&#xff1a; from sklearn.da…