0

0

[UWP 自定义控件]了解模板化控件(5):VisualState

雪夜

雪夜

发布时间:2025-10-02 10:18:36

|

931人浏览过

|

来源于php中文网

原创

  1. 功能需求

使用templatepart实现上篇文章的两个需求(header为空时隐藏headercontentpresenter,鼠标没有放在控件上时headercontentpresent半透明),虽然功能已经实现,但这种实现方式几乎无法进行扩展。例如,开发者无法通过继承或修改controltemplate来实现以下功能:

  • 半透明时的Opacity不是0.7,而是0.5。
  • 半透明和不透明之间切换时有渐变动画。

当然,这些需求也可以通过代码实现,但会变得更加复杂。大多数开发者熟悉C#,对XAML不太了解,容易选择用C#实现所有功能,将所有功能集中在一个地方并使用熟悉的语言处理。这种方法虽然有其优点,但既然在使用XAML平台,就应该尽可能利用XAML平台UI和代码分离的优点。

本文将使用ContentView2示例讲解VisualState如何实现上述需求,ContentView2和上篇文章的ContentView一样继承自HeaderedContentControl。

  1. VisualState在实现需求前首先解释VisualState的概念

VisualState指定控件处于特定状态时的外观。控件的代码指定控件处于何种状态,控件的ControlTemplate中根节点包含VisualStateManager.VisualStateGroups附加属性,并在其中确定各个VisualState的外观。

以CheckBox为例,CheckBox基本上包含Unchecked、Checked、Indeterminate三种状态,它通过IsChecked的值在这三种状态中转换。

[UWP 自定义控件]了解模板化控件(5):VisualState这三种状态的外观如下所示:

[UWP 自定义控件]了解模板化控件(5):VisualState3. 确定VisualState要使用VisualState,首先要明确控件中包含哪些VisualState

在ContentView2中有两组VisualState:

  • CommonStates: 默认是“Normal”,当鼠标进入控件时是“PointerOver”。
  • HeaderStates: 默认是“NoHeader”,当Header属性的值不为空时是“HasHeader”。

其中“CommonStates”、“HeaderStates”称为VisualStateGroup,“Normal”、“PointerOver”等称为VisualState。在同一个VisualStateGroup中的VisualState是互斥的,控件始终只能处于每组状态中的一种。例如,控件只能处于NoHeader状态,或者HasHeader状态。

模板化控件可以使用TemplateVisualStateAttribute协定声明它的VisualState,用于通知控件的使用者有这些VisualState可用。TemplateVisualStateAttribute是可选的,而且就算控件声明了这些VisualState,ControlTemplate也可以不包含它们中的任何一个,并且不会引发异常。

ContentView2的TemplateVisualStateAttribute如下:

标小兔AI写标书
标小兔AI写标书

一款专业的标书AI代写平台,提供专业AI标书代写服务,安全、稳定、速度快,可满足各类招投标需求,标小兔,写标书,快如兔。

下载
[TemplateVisualState(Name = NormalState, GroupName = CommonStates)]
[TemplateVisualState(Name = PointerOverState,GroupName =CommonStates)]
[TemplateVisualState(Name = NoHeaderState, GroupName = HeaderStates)]
[TemplateVisualState(Name = HasHeaderState, GroupName = HeaderStates)]
public class ContentView2 : HeaderedContentControl{
    public const string CommonStates = "CommonStates";
    public const string NormalState = "Normal";
    public const string PointerOverState = "PointerOver";
    public const string HeaderStates = "HeaderStates";
    public const string NoHeaderState = "NoHeader";
    public const string HasHeaderState = "HasHeader";
}
  1. VisualStateManagerVisualStateManager用于管理VisualState并操作它们之间的转换
public ContentView2(){
    this.DefaultStyleKey = typeof(ContentView2);
}
private bool _isPointerEntered;
protected override void OnApplyTemplate(){
    base.OnApplyTemplate();
    UpdateVisualState(false);
}
protected override void OnPointerEntered(PointerRoutedEventArgs e){
    base.OnPointerEntered(e);
    _isPointerEntered = true;
    UpdateVisualState();
}
protected override void OnPointerExited(PointerRoutedEventArgs e){
    base.OnPointerExited(e);
    _isPointerEntered = false;
    UpdateVisualState();
}
protected override void OnHeaderChanged(object oldValue, object newValue){
    base.OnHeaderChanged(oldValue, newValue);
    UpdateVisualState();
}
internal virtual void UpdateVisualState(bool useTransitions = true){
    if (_isPointerEntered)
        VisualStateManager.GoToState(this, PointerOverState, useTransitions);
    else
        VisualStateManager.GoToState(this, NormalState, useTransitions);
    if (Header == null)
        VisualStateManager.GoToState(this, NoHeaderState, useTransitions);
    else
        VisualStateManager.GoToState(this, HasHeaderState, useTransitions);
}

ContentView2的其它代码如上所示,在OnApplyTemplate、OnHeaderChanged及鼠标进入离开时使用VisualStateManager.GoToState(Control control, string stateName,bool useTransitions)更新VisualState。useTransitions这个参数指示是否使用 VisualTransition 进行状态过渡,简单来说即是VisualState之间切换时用不用VisualTransition里面定义的动画。

注意OnApplyTemplate中的这句代码:UpdateVisualState(false)。控件在加载ControlTemplate时就需要确定它的状态,一般这时候都不会使用过渡动画。

VisualStateManager.GoToState不会使控件重复进入某个状态,譬如如果控件已处于PointerOverState,再次调用VisualStateManager.GoToState(this, PointerOverState, useTransitions)不会触发任何操作,也不会打断正在执行的过渡动画或重复触发动画。

到这里为止ContentView2.cs的工作已经完成,接下来就是XAML的责任了。

  1. 使用Blend编辑ControlTemplate使用Blend编辑ContentView2的空白ControlTemplate时,由于已经声明了TemplateVisualStateAttribute,可以看到在“状态”窗口已经默认就有定义好的状态

[UWP 自定义控件]了解模板化控件(5):VisualState编辑后结果如下:


    
        
            
                
                    
                
            
        
        
            
                
            
        
        
            
                
            
        
    
    
        
            
                
            
        
        
        
    

[UWP 自定义控件]了解模板化控件(5):VisualState从XAML中可以看出VisualState子节点的Setter是关键所在,如PointerOver的VisualState通过Setter将HeaderContentPresenter的Opacity更改为1,满足了“当鼠标移动到控件控件上时,设置Header的Opacity=1”这个需求。

另外,VisualStateGroup.Transitions 节点定义了CommonStates在各个状态之间切换时的过渡动画。VisualStateManager.GoToState(this, PointerOverState, useTransitions) 中的参数useTransitions即是控制是否使用过渡动画。示例中使用的过渡动画为CubicEase,过渡时间为0.5秒。

需要注意的是不同VisualStateGroup之间尽量不要对同一个UI元素的同一个属性进行操作,否则会引起冲突。

这个主题不会详细讲解使用Blend修改VisualState,因为那会占用很多篇幅。幸好Blend在这方面做得很容易上手,而且多年来基本操作都没有变过,可以在网上找到很多这方面的文章。

  1. **结论很多时候VisualState方式并不会比TemplatePart方式少写代码,譬如ContentView2的代码量就基本和ContentView一致,而XAML行数还更多。但VisualState的实现方式更灵活,更加符合UI与代码分离原则及开放封闭原则。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

316

2023.08.02

C++ 单元测试与代码质量保障
C++ 单元测试与代码质量保障

本专题系统讲解 C++ 在单元测试与代码质量保障方面的实战方法,包括测试驱动开发理念、Google Test/Google Mock 的使用、测试用例设计、边界条件验证、持续集成中的自动化测试流程,以及常见代码质量问题的发现与修复。通过工程化示例,帮助开发者建立 可测试、可维护、高质量的 C++ 项目体系。

9

2026.01.16

java数据库连接教程大全
java数据库连接教程大全

本专题整合了java数据库连接相关教程,阅读专题下面的文章了解更多详细内容。

32

2026.01.15

Java音频处理教程汇总
Java音频处理教程汇总

本专题整合了java音频处理教程大全,阅读专题下面的文章了解更多详细内容。

14

2026.01.15

windows查看wifi密码教程大全
windows查看wifi密码教程大全

本专题整合了windows查看wifi密码教程大全,阅读专题下面的文章了解更多详细内容。

42

2026.01.15

浏览器缓存清理方法汇总
浏览器缓存清理方法汇总

本专题整合了浏览器缓存清理教程汇总,阅读专题下面的文章了解更多详细内容。

6

2026.01.15

ps图片相关教程汇总
ps图片相关教程汇总

本专题整合了ps图片设置相关教程合集,阅读专题下面的文章了解更多详细内容。

9

2026.01.15

ppt一键生成相关合集
ppt一键生成相关合集

本专题整合了ppt一键生成相关教程汇总,阅读专题下面的的文章了解更多详细内容。

6

2026.01.15

php图片上传教程汇总
php图片上传教程汇总

本专题整合了php图片上传相关教程,阅读专题下面的文章了解更多详细教程。

2

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.3万人学习

Excel 教程
Excel 教程

共162课时 | 12.1万人学习

PHP基础入门课程
PHP基础入门课程

共33课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号