WPF_12_控件模板


模板和样式是相互补充的,允许用户对控件进行重新设计。想要重新设计控件,我们就要先了解控件的逻辑树和可视化树。WPF提供了用于浏览逻辑树和可视化树的两个类:

  • System.Windows.LogicalTreeHelper
  • System.Windows.Media.VisualTreeHelper

LogicalTreeHelper类提供了几个方法:

方法名 说明
FindLogicalNode() 根据名称查找特定元素,从指定的元素开始并向下查找逻辑树
BringIntoView() 将元素滚动到视图中
GetParent() 获取指定元素的父元素
GetChildren() 获取指定元素的子元素

与此类似,VisualTreeHelper 类还提供了 GetChildrenCount() , GetChild() , GetParent() .可视化树是逻辑树的扩展版本,将元素分成更小的部分,这些部分都是由 FrameworkElement 类的派生类表示的。

每个控件都有一个内置的方法,用于确定如何渲染控件(作为一组更基础的元素)。这个方法称为 控件模板(control template) ,是用XAML标记块定义的。

控件模板定义构成控件的元素。在WPF中有三种类型的模板,都继承自 FrameworkTemplate 基类。控件模板(由ControlTemplate类表示),数据模板(由DataTemplate和HierachicalDataTemplate类表示),面板模板(由ItemsPanelTemplate类表示)。

下面是普通 Button 类的模板的简化版本:


    
    
        
        
    
    
        
            
            
                
                    True
                
            
            
                True
            
        
        
            
                
                    True
                
            
            
                True
            
        
    

可以使用 Snoop 工具深入研究程序的可视化树。或者通过一个简单的工具 WPFControl

创建控件模板


    
        
        
            
            
        
        
    



模板和样式有类似之处,都能改变元素的外观。然而,样式被限制在一个小得多的范围,可调整控件的属性但不能使用全新的由不同元素组成的可视化树代替控件原来的外观。

控件模板应用于多个窗口,也可以用于整个程序。为避免多次定义,可在 Application 类的 Resources 集合中定义模板资源。为每个控件创建单独的资源字典是推荐的方式,并添加到特定窗口或应用程序(更常见)的Resources 集合中。可使用 MergedDictionaries 集合完成该工作。


    
        
            
                
            
        
    

如果希望重用这些具有不同格式细节(通常是颜色和字体)元素,可从模板中将这些细节提取出来,并将它们放到样式中。



    
        
            
            
            
        
    
    
        
            
            
        
    

关联的样式应用这个控件模板,设置边框和背景色颜色,并添加触发器以便根据按钮的状态改变背景色:


为使用这个模板,需要设置按钮的 Style 属性而不是 Template 属性:


理想情况,能在控件模板中保留所有触发器,因为它们代表控件的行为,并使用简单设置基本属性。但如果希望样式能够设置颜色方案,是不可能实现的。如果在控件模板和样式中都设置了触发器,那么样式触发器具有优先权

包含基于类型的样式的组合的资源字典通常被称为 主题(theme) 。通过主题可以为已有程序的所有控件重新应用皮肤,而不需要更改用户界面标记。需要为项目添加资源字典,并将其合并到 App.xaml 文件的 Application.Resources 集合中。


    
        
    

当允许用户选择皮肤时,在于检索 ResourceDictionary 对象:

ResourceDictionary newDictionary = new ResourceDictionary();
newDictionary.Source = new Uri("Resources/GradientButtonVariant.xaml", UriKind.Relative);

// Window
this.Resources.MergedDictionaries[0] = newDictionary;
// Application
Application.Current.Resources.MergedDictionaries[0] = newDictionary;

我的公众号

WPF