• 正确理解WPF中的TemplatedParent


    (注:Logical Tree中文称为逻辑树,Visual Tree中文称为可视化树或者视觉树,由于名称不是很统一,文中统一用英文名称代表两个概念,况且VisualTreeHelper和LogicalTreeHelper也是WPF中提供的类名称)

    众所周知WPF中的Logical Tree是逻辑上定义的元素层次树,而实际上显示在屏幕上的元素层次树是Visual Tree,Visual Tree是Logical Tree节点扩充后的的产物。因此从Visual Tree的角度上看(Visual Tree当然是完整的一个),Logical Tree被分割成一段一段的,而这些段与段的连接点,就是和TemplatedParent有关。

    这个概念在WPF类模型中是FrameworkElement.TemplatedParent属性。WPF中的模板(数据模板和控件模板)都可以扩展Logical Tree,那么模板所修饰的对象就是模板中元素的TemplatedParent,此时模板元素和修饰对象都会出现在Visual Tree中,但模板元素肯定不属于被修饰元素的Logical Tree,但是模板有自己的Logical Tree,两个Logical Tree是分开的,但是通过TemplatedParent,两者之间又有联系。

    说再多不如实例形象,来看下面示例代码:

    这是一个简单的ContentControl,它的Content是一个按钮,然后定义了控件模板和数据模板,代码中一些关键元素有Name属性,我们在后续讨论就以Name属性的值来引用这些元素。

    [html] view plain copy
     
    1. <ContentControl Name="contentControl">  
    2.   
    3.               
    4.   
    5.     <!-- 控件模板 -->  
    6.   
    7.     <ContentControl.Template>  
    8.   
    9.         <ControlTemplate TargetType="ContentControl">  
    10.   
    11.             <Border Name="bd1">  
    12.   
    13.                 <ContentPresenter Name="cp1" ContentSource="Content"/>  
    14.   
    15.             </Border>  
    16.   
    17.          </ControlTemplate>  
    18.   
    19.      </ContentControl.Template>  
    20.   
    21.               
    22.   
    23.      <!-- 数据模板 -->  
    24.   
    25.      <ContentControl.ContentTemplate>  
    26.   
    27.          <DataTemplate>  
    28.   
    29.              <Border Name="bd2">  
    30.   
    31.                  <ContentPresenter Name="cp2" Content="{Binding}" />  
    32.   
    33.              </Border>  
    34.   
    35.           </DataTemplate>  
    36.   
    37.       </ContentControl.ContentTemplate>  
    38.   
    39.               
    40.   
    41.       <!-- 逻辑孩子 -->  
    42.   
    43.       <Button Name="btn">按钮</Button>  
    44.   
    45. </ContentControl>  

    这个ContentControl的Visual Tree如下图:

    图中相同颜色的节点代表它们属于同一个Logical Tree,可以看出来,整个Visual Tree分成多个Logical Tree,而这些Logical Tree是分开的,比如上面代码中的两个Border(名称是bd1和bd2),它们的Parent属性的值都是null,即没有逻辑父节点。但是这些逻辑树通过TemplatedParent是互相有联系的。比如控件模板中的元素的TemplatedParent指代最上方的ContentControl,而数据模板元素的TemplatedParent则是控件模板内的ContentPresenter元素

    通过代码也可以验证这些:(bd1, bd2, cp1, cp2分别代表控件模板和数据模板中的Border和ContentPresenter)

    [csharp] view plain copy
     
    1. private void Button_Click(object sender, RoutedEventArgs e)  
    2.   
    3. {  
    4.   
    5.     var bd1 = (Border)contentControl.Template.FindName("bd1", contentControl);  
    6.   
    7.     var cp1 = (ContentPresenter)contentControl.Template.FindName("cp1", contentControl);  
    8.   
    9.     var bd2 = (Border)contentControl.ContentTemplate.FindName("bd2", cp1);  
    10.   
    11.     var cp2 = (ContentPresenter)contentControl.ContentTemplate.FindName("cp2", cp1);  
    12.   
    13.    
    14.   
    15.     PrintInfo(bd1, cp1, bd2, cp2, btn);  
    16.   
    17. }  
    18.   
    19.    
    20.   
    21. void PrintInfo(params FrameworkElement[] eles)  
    22.   
    23. {  
    24.   
    25.     string s = "";  
    26.   
    27.     foreach (var ele in eles)  
    28.   
    29.         s += String.Format("{2} Parent: {0} TemplatedParent: {1} ", ele.Parent, ele.TemplatedParent, ele.Name);  
    30.   
    31.     MessageBox.Show(s);  
    32.   
    33. }  


    输出信息:(冒号后没有值则代表null)

    [plain] view plain copy
     
    1. bd1  
    2. Parent:     
    3. TemplatedParent: System.Windows.Controls.ContentControl: 按钮  
    4. cp1  
    5. Parent: System.Windows.Controls.Border  
    6. TemplatedParent: System.Windows.Controls.ContentControl: 按钮  //Parent & templateparent是不同概念
    7.   
    8. bd2   
    9. Parent:    
    10. TemplatedParent: System.Windows.Controls.ContentPresenter  
    11.    
    12. cp2  
    13. Parent: System.Windows.Controls.Border   
    14. TemplatedParent: System.Windows.Controls.ContentPresenter  
    15.    
    16. btn  
    17. Parent: System.Windows.Controls.ContentControl: 按钮  
    18. TemplatedParent:   


     

    最后还有一个btn,指代ContentControl中的内容按钮,它属于主干逻辑树,因此Parent是ContentControl,同时它也不属于任何模板,不存在修饰对象,因此TemplatedParent为null

    另外WPF数据绑定Binding类还支持RelativeSource对象,这个RelativeSource类的Mode属性有一个TemplatedParent值,这个值就是代表数据绑定会将数据源作为,同时WPF中的TemplateBinding标记扩展可以方便定义此类绑定,另外TemplateBinding的绑定模式是OneWay。

    了解了TemplatedParent,使用TemplateBinding也就非常灵活了,一般情况下TemplateBinding使用在定义控件模板下,但是在数据模板中也可以使用,比如下面这个例子:

    [html] view plain copy
     
    1. <ContentControl>  
    2.   
    3.     <Button>Content</Button>  
    4.   
    5.     <ContentControl.ContentTemplate>  
    6.   
    7.         <DataTemplate>  
    8.   
    9.             <ContentPresenter Content="{TemplateBinding Content}" />  
    10.   
    11.         </DataTemplate>  
    12.   
    13.     </ContentControl.ContentTemplate>  
    14.   
    15. </ContentControl>  


    这个TemplateBinding的数据源在哪里?答案就是ContentControl中默认控件模板里的ContentPresenter,所以这里数据模板内的ContentPresenter的Content直接绑定到控件模板中的ContentPresenter的Content属性,当然这个仅仅为了做示例,实际上用Content=”{Binding}”也可以。

  • 相关阅读:
    Android UI开发第三十二篇——Creating a Navigation Drawer
    Asynchronous HTTP Requests in Android Using Volley
    AndroidHttp通信 HTTP Client与HttpURLConnection的区别
    Volley使用详细说明
    网络通信框架Volley使用详细说明
    Google I/O 2013 – Volley: Easy, Fast Networking for Android
    Android UI开发第三十一篇——Android的Holo Theme
    存储过程多值参数报表
    报表如何嵌入到网页并接收参数?
    多选参数可为空报表的实现方法
  • 原文地址:https://www.cnblogs.com/sjqq/p/8454575.html
Copyright © 2020-2023  润新知