--转载

在使用TabControl、ListView、Menu、TreeView的时候被各种Template搞得头昏眼花,决心把这个问题搞清楚,究竟什么时候该用什么Template?这是个麻烦的问题,欠揍的表达方法是“根据俺这么多年写程序的经验,这是一个需要经验才能解决的问题”。首先看一下相关几个类的层次结构:
Control
  |
  +---- ContentControl
  |       |
  |       +---- ListBoxItem
  |       |
  |       +---- HeaderedContentControl
  |               |
  |               +---- TabItem
  |
  +---- ItemsControl
          |
          +---- TreeView
          |
          +---- MenuBase
          |
          +---- HeaderedItemsControl
          |       |
          |       +---- MenuItem
          |       |
          |       +---- TreeViewItem
          |
          +---- Selector
                  |
                  +---- TabControl
                  |
                  +---- ListBox

 
值得关注的类有四个,为了简单清楚起见,给他们重新起名字:
  1. ContentControl:无标题的单元素容器
  2. HeaderedContentControl:有标题的单元素容器
  3. ItemsControl:无标题的多元素容器
  4. HeaderedItemsControl:有标题的多元素容器
各个类有不同的Template,引发我头疼症状的一共有3个,也给他们重新起名字:
  1. ContentTemplate:单元素的容器画单子元素的画笔
  2. ItemTemplate:多元素的容器画每个子元素的画笔
  3. HeaderTemplate:有标题的容器画标题的画笔
好,一切到目前为止都很清晰。再来看看各个类都有哪些画笔:
  1. ContentControl:无标题的单元素容器,只有画单子元素的画笔
  2. HeaderedContentControl:有标题的单元素容器,显而易见,比上面多了一个画标题的画笔
  3. ItemsControl:无标题的多元素容器,只有一个画每个子元素的画笔ItemTemplate
  4. HeaderedItemsControl:有标题的多元素容器,也是显而易见,多了一个画标题的画笔
同样,一切都是理所当然,显而易见。然而这时,混乱产生了:当“容器”和“元素”搭配到一起的时候,各种画笔就开始复杂起来了。现在来分析几个典型的容器和元素的搭配:

1、TabControl和TabItem

TabControl本身是一个无标题的多元素容器,按上面所述,没有标题画笔,只有一个画每个子元素的ItemTemplate画笔。
他肚子里的元素是TabItem,这是一个有标题的单元素容器,有两个画笔,ContentTemplate和HeaderTemplate。那么TabItem的画笔和TabControl的画笔是什么关系呢?
事实上我撒谎了:TabControl有两个画笔,ContentTemplate和ItemTemplate,而不是一个,其中ItemTemplate继承自父类,而ContentTemplate是他自己重新定义的一个属性——好,我们终于抓住了这个伪造身份证扰乱社会治安破坏和谐社会的家伙。这种做法虽然很混淆,但是带来了方便,容器和元素的对应关系是
  • TabItem的HeaderTemplate就是TabControl的ItemTemplate
  • TabItem的ContentTemplate就是TabControl的ContentTemplate

2、Menu和MenuItem

Menu只有一个ItemTemplate,MenuItem有HeaderTemplate和ItemTemplate。这里其实有两个搭配,一个是Menu和MenuItem的搭配,另一个是MenuItem和MenuItem的搭配。在这两个搭配中,有以下共同点:
  • 容器的ItemTemplate变成元素的HeaderTemplate
  • 每个MenuItem都用自己对应的HeaderTemplate来显示自己

这是一个分级的结构,WPF提供了HierarchicalDataTemplate,很方便,不过暂时先不说这个,免得问题更加复杂化。

3、TreeView和TreeViewItem

从上面的类层次结构可以看出,这个搭配和Menu/MenuItem的情况应该是一样的,事实上在XAML中很容易在TreeView和Menu之间切换,容易到了只需要改几个tag就可以,可见两者是“同构”的。

4、ListBox和ListBoxItem

ListBox本身是一个无标题的多元素容器,只有一个ItemTemplate。ListBox是遵纪守法的好同志,不像TabControl伪造了一个ContentTemplate。他的ItemTemplate就是ListBoxItem的ContentTemplate,并且ListBoxItem也没有其他的画笔了,这一对组合是最简单的。

05-08 08:35