• DataTemplate和ControlTemplate的关系


    在wp/silverlight/wpf也会经常看到控件模板。经常混淆的应该是DataTemplate和ControlTemplate,本篇文章就来谈谈两件衣服DataTemplate和ControlTemplate的关系。本篇文章主要会以wpf控件为主,以便最后的源码大家都可以打开。

    一、ContentControl中的DataTemplate

    在开始之前,我们先去看一下ContentControl的定义,无论在wp还是在wpf中其都有下面两个属性:
    public object Content { get; set; }
    public DataTemplate ContentTemplate { get; set; }

    其特点是只能容纳一个内容,内容类型是object类型,其中Button控件是我们大家比较熟悉且属于ContentControl的类,下面我们看一下直接使用TextBlock作为其内容,Button会工作的很好。如下图:

    image

    这个很正常,因为内容是object的嘛,那么下面我就使用另外一种笔刷作为其内容。看结果:

    image

    显示内容成了笔刷转化后的字符串。如果是在回头看看DataTemplate的话,会发现其摘要是:

    获取或设置用于显示 System.Windows.Controls.ContentControl 内容的数据模板。内容的数据模板也就是说内容以什么样子表现出来。

    下面我就让button的内容-笔刷在一个圆上显示出来。

    image

    以上我使用了button内容控件是实现了用圆形来展示button的内容。当然推而广之,我可以使用任何内容控件,先设置其Content(该内容可以是任何复杂的内容),然后使用DataTemplate来表达Content的数据。下面我们就使用一个UserControl控件来实现一个同学的信息:定义一个Student类,然后初始化一个stu,设置其为UC的Content,然后罗列出Content中的数据。

    image

    由上面的两个例子可以得出的结论是ContentControl中的DataTemplate是用来表示Content中的数据的,也就是说Content是DataTemplate的绑定的源,具体的表现形式是由DataTemplate决定的。

    二、Control的ControlTemplate

    在Control中,有个Template属性,其摘要和返回结果如下:

    // 摘要:
    //     获取或设置控件模板。
    // 返回结果:
    //     用于定义 System.Windows.Controls.Control 的外观的模板。
    public ControlTemplate Template { get; set; }

    和DataTemplate不一样的是:该控件定义外观模板。我们还以Button为例子吧。上面返回结果说了是外观的模板,那我想要一个圆角的Button,应该属于外观的范畴了,很快我想到了使用Border.下面就开工吧。我先弄个按钮,给他写上内容和加上背景颜色:

    image

    然后加上Template属性,结果发现背景颜色和内容都没有了。

    image
    如果是按照这样的写法,上面的结果可以看到Content没有abc了。为了显示出来abc我是不是可以在Border里面加个控件TextBlock,然后在 TextBlock上面写上几个字母,发现可以显示了,但是如果是写的不是abc,还是不能显示abc,说明现在显示的内容的决定于TextBlock,如果能有一种绑定的话多好呢,我就可以让TextBlock显示的和abc的一致了。有个TemplateBinding,使用时要在ControlTemplate标签中使用Target。效果如下:

    image

    虽然效果实现了,但是有个很严重的问题是我们的Button的Content是object类型,Text是一个字符串类型。如果是button什么时间心情不好,Content属性变成Image了,那是不是我要跟着“Button”受气呢?为了不受气,想一下有没有使用于所有类型内容的容器呢?答案是肯定的。使用ContentPresenter。现在无论你是图片还是文字,我都不用鸟你,都有ContentPresenter照着。下面亮出来他的样子

    image

    ContentPresenter非常标准,他会为你自动匹配Target的Content和ContentTemplate。如果Button.Content有关的属性(如FontSize,Foreground,FontFamily等)发生变化了,不用做任何更改ContentPresenter会帮我们处理的很好,但是如果是和Button本身有关的属性,(如背景色等),需要显式的调整。

    三、DataTemplate和ControlTemplate联系

    在上面的例子中使用ContentPresenter时,会发现其也有一个ContentTemplate,是不是会猜出来是DataTemplate类型的,而且是在Template树上"长着"。由此可以猜想ContentTemplate对应的DataTemplate是Template对应的ControlTemplate树上的一棵子树。为了证明这个事实,下面我还以Button来说明。

    现在我分别在button里面使用文字,图片,笔刷作为button的内容,然后添加一个容器来显示Template的子树,下面是xaml代码:

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Button Grid.Row="0" Grid.Column="0"
                        Content="Click to Dump"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        Click="OnButtonClick" />
                <Button Grid.Row="0" Grid.Column="1"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        Click="OnButtonClick">
                    <Image Source="Images/vs.png"
                           Stretch="None" />
                </Button>
                <Button Grid.Row="1" Grid.ColumnSpan="2"
                        HorizontalAlignment="Center"
                        VerticalAlignment="Center"
                        Click="OnButtonClick">
                    <Button.Content>
                        <RadialGradientBrush>
                            <GradientStop Offset="0" Color="Blue" />
                            <GradientStop Offset="1" Color="AliceBlue" />
                        </RadialGradientBrush>
                    </Button.Content>
                    <Button.ContentTemplate>
                        <DataTemplate>
                            <Ellipse Width="100" Height="100" Fill="{Binding}" />
                        </DataTemplate>
                    </Button.ContentTemplate>
                </Button>
                <ScrollViewer Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2"
                              HorizontalScrollBarVisibility="Auto">
                    <StackPanel Name="stackPanel" />
                </ScrollViewer>
        </Grid>

    我可以根据可视树的查找(VisualTreeHelper类提供的方法结合递归算法)来查看Button中的Template下面都有哪些子树。下面代码是后台代码:

    public partial class MainWindow : Window 
       { 
           public MainWindow() 
           { 
               InitializeComponent(); 
               
           } 
           void OnButtonClick(object sender, RoutedEventArgs args) 
           { 
               Button btn = sender as Button; 
               stackPanel.Children.Clear(); 
               DumpVisualTree(btn, 0); 
           }
    
           void DumpVisualTree(DependencyObject parent, int indent) 
           { 
               TextBlock txtblk = new TextBlock(); 
               txtblk.Text = String.Format("{0}{1}", new string(' ', 4 * indent), 
                                                     parent.GetType().Name); 
               stackPanel.Children.Add(txtblk);
    
               int numChildren = VisualTreeHelper.GetChildrenCount(parent);
    
               for (int childIndex = 0; childIndex < numChildren; childIndex++) 
               { 
                   DependencyObject child = VisualTreeHelper.GetChild(parent, childIndex); 
                   DumpVisualTree(child, indent + 1); 
               } 
           } 
       } 

    image

    分别点击各个按钮,可以看到各个按钮的Template是怎么构造的,有个共同的特点可视树都包含有ContentPresenter,这不正说明了DataTemplate被ContentPresenter替代掉了,说明的是DataTemplate生成的是ContentPresenter以下的树(wp和silverlight中ContentPresenter以下的树可能和wpf上面有些不一样)。也验证了DataTemplate是ControlTemplate的子树的一部分。

    四、总结

    本文主要通过介绍DataTemplate和ControlTemplate,然后引入ContentPresenter,通过可视树的帮助类VisualTreeHelper类查看控件所包含的模板内容,进而验证了DataTemplate和ControlTemplate的关系。如果你觉得本文哪里有说的不对的地方,欢迎指正!感谢阅读!

    源码下载:http://files.cnblogs.com/lzhp/TemlateDemo.zip

  • 相关阅读:
    windows命令
    idea 操作git
    zookeeper常见问题
    utf8编码
    烟火云雾识别比赛
    虚树学习笔记
    圆方树学习笔记
    ROS的TF坐标变换
    bootchart
    指定位置读取bin文件中有效信息
  • 原文地址:https://www.cnblogs.com/lzhp/p/3250786.html
Copyright © 2020-2023  润新知