前段時間在項目開發中需要用 TreeListView 的功能,於是在網上狂搜一通,倒也找到了幾個小例子,但還是滿足不了我簡單的要求,由於時間緊也只能折中湊合着用了。最近時間比較充裕,把其中的例子整理一下分享給大家。在文章最后部分還有一個沒解決的問題,也希望得到牛人的指點,小弟不勝感激 O(∩_∩)O~
文章中使用的是msdn提供的示例,源代碼下載 - TreeListView.zip。修改后的程序代碼下載 - TreeListViewSample.zip,修改前后的程序界面如下:

修改前

修改后
1 綁定數據
在msdn示例中,數據是直接寫在 xaml文件中進行綁定的,如下所示:
<l:TreeListView>
<l:TreeListViewItem>
<l:TreeListViewItem.Header>
<x:Type TypeName="DependencyObject" />
</l:TreeListViewItem.Header>
<l:TreeListViewItem>
<l:TreeListViewItem.Header>
<x:Type TypeName="Visual" />
</l:TreeListViewItem.Header>
......
<l:TreeListViewItem>
<l:TreeListViewItem.Header>
<x:Type TypeName="GridViewColumnCollection" />
</l:TreeListViewItem.Header>
</l:TreeListViewItem>
<l:TreeListViewItem>
<l:TreeListViewItem.Header>
<x:Type TypeName="GridViewColumnHeaderRole" />
</l:TreeListViewItem.Header>
</l:TreeListViewItem>
</l:TreeListView>
這種做法的弊端不用多說,在我們實際開發過程中是絕對不允許的,下面我把它改成了基於MVVM的數據綁定方式。首先用 NuGet插件管理引入 MvvmLight,然后在Model中添加Staff類,Staff類中定義了一些在界面上顯示的屬性,在 ViewModel中添加 MainViewModel類,用來生成一些綁定到界面的測試數據,並將 MainViewModel實例賦值給 MainWindow的 DataContext:
MainViewModel vm = new MainViewModel(); this.DataContext = vm;
數據源准備完畢,接着就是對界面顯示的改動,將綁定列的集合GridViewColumnCollection 改為下面的代碼:
<GridViewColumnCollection x:Key="gvColumns"> <GridViewColumn Header="姓名" CellTemplate="{StaticResource CellTemplate_Name}" Width="100" /> <GridViewColumn Header="年齡" DisplayMemberBinding="{Binding Age}" Width="80" /> <GridViewColumn Header="性別" DisplayMemberBinding="{Binding Sex}" Width="80" /> <GridViewColumn Header="職務" DisplayMemberBinding="{Binding Duty}" Width="100" /> </GridViewColumnCollection>
最后一步,也是最關鍵的一步是給 TreeListView綁定數據源:
<l:TreeListView Background="WhiteSmoke" BorderBrush="#FF32C1FF" ItemsSource="{Binding StaffList}"> <l:TreeListView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding StaffList}" /> </l:TreeListView.ItemTemplate> </l:TreeListView>
完成以上步驟,運行程序即可看到如下界面,動態創建的數據已經綁定到 TreeListView:

2 添加滾動條
按說能夠動態的顯示數據,主要的功能就算完成了,但在實際開發中許多細節的方面的東西還是需要考慮地,於是,為了 TreeListView能夠更好的在程序中使用,就需要考慮更多的細節。運行 msdn提供的示例會發現顯示內容超出控件本身的范圍時並沒有滾動條出現,下面是 msdn 中 TreeListView的樣式:
<Style TargetType="{x:Type l:TreeListView}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type l:TreeListView}"> <Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"> <DockPanel> <GridViewHeaderRowPresenter Columns="{StaticResource gvColumns}" DockPanel.Dock="Top"/> <ItemsPresenter /> </DockPanel> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
我們可以看到最外層是Border,其內部是DockPanel,Panel包含了 GridViewHeaderRowPresenter(頭部)和 ItemsPresenter(內容)兩部分。根本就沒有發現 ScrollViewer的影子,不出現滾動條也不奇怪了,下面的代碼給它添加上了ScrollViewer:
<Style TargetType="{x:Type l:TreeListView}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type l:TreeListView}"> <Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"> <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled"> <DockPanel> <GridViewHeaderRowPresenter Columns="{StaticResource gvColumns}" DockPanel.Dock="Top"/> <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <ItemsPresenter /> </ScrollViewer> </DockPanel> </ScrollViewer> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
這里可能有人會有疑問為什么添加兩個ScrollViewer,只用外層的 ScrollViewer 並把屬性VerticalScrollBarVisibility 設置為Auto不行嗎?這樣做也是可行的,只是在垂直滾動時列表標題行也會跟隨滾動條滾動,而不是固定在頂端。
3 選中、展開節點
利用第一部分數據綁定的方式也可以實現自動選中、展開節點,在 Staff類中添加如下屬性:
private bool _IsSelected; private bool _IsExpanded; /// <summary> /// 是否選中 /// </summary> public bool IsSelected { get { return _IsSelected; } set { _IsSelected = value; this.RaisePropertyChanged("IsSelected"); } } /// <summary> /// 是否展開 /// </summary> public bool IsExpanded { get { return _IsExpanded; } set { _IsExpanded = value; this.RaisePropertyChanged("IsExpanded"); } }
然后在 TreeListViewItem樣式中,添加如下代碼即可實現此功能:
<Setter Property="IsSelected" Value="{Binding IsSelected}" /> <Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
4 鼠標滑過改變背景色
對於 TreeListViewItem,在 Template的 ControlTemplate.Triggers中添加如下代碼,即可實現此功能:
<Trigger Property="IsMouseOver" Value="true" SourceName="innerBorder"> <Setter Property="Foreground" Value="White"/> <Setter Property="Background" Value="#FFC66152" TargetName="innerBorder"/> </Trigger>
5 交替行樣式
前面幾部分把修改的主要部分進行了介紹,文章最后當然是提出那個沒有解決的問題。
當看到文章開始部分修改后的程序截圖時,您可能已經有怪怪的感覺,怎么行的背景色是這么變化的,雜亂無章,讓它交替改變背景色多好!( ⊙ o ⊙ )是的,我也是想做出那樣的效果,只是沒有能夠找到解決的方法,在此懇請牛人指點一二,多謝!
