WPF如何用TreeView制作好友列表、播放列表
前言
TreeView這個控件對於我來說是用得比較多的,以前做的小聊天軟件(好友列表)、音樂播放器(播放列表)、類庫展示器(樹形類結構)等都用的是TreeView,下面以一個好友列表為例,說明一下制作過程,這個過程可以搬遷到其他類似的場景中去(樹形結構的場景)。
結果展示
制作過程
一:新建一個WPF工程,我命名為TreeViewDemo。(這步不解釋)
二:准備圖片,就是系統頭像。在工程中新建一個Heads文件夾,並且添加系統頭像圖片,最后不要忘記需要把生成方式改為Resource、不復制,這樣才能用標准的Pack URI的方式來讀取到圖片。(我喜歡用Pack Uri,因為比較通用,安全) 下載頭像
三:好了,資源圖片准備好了以后,來定義數據類,在這里我們需要用到兩個類,一個代表好友,一個代表好友列表(對應的音樂播放器就是音樂和音樂列表)。
1.Friend(好友)
class Friend { public Friend(FriendList list) { this.List = list; } //頭像的路徑 public String HeadPath { set; get; } //好友名字 public String Name { set; get; } //簽名 public String Autograph { set; get; } public FriendList List { set; get; } }
2.FriendList(好友列表)
class FriendList { public FriendList(String name) { this.ListName = name; } public String ListName { set; get; } private ObservableCollection<Friend> _friends = new ObservableCollection<Friend>(); public ObservableCollection<Friend> Friends { private set{} get { return _friends; } } public void AddFriend(Friend newFriend) { _friends.Add(newFriend); } public void RemoveFriend(Friend friend) { _friends.Remove(friend); } }
四:這一步是重點,就是在一個TreeView的節點中,如何去區分Friend和FriendList呢?我使用模板,我分別為Friend和FriendList定義屬於它們各自的模板,一起定義在一個字典中,新建一個字典,我命名為GlobeDictionary。這里應該要用的是數據模板(DataTemplate),系統有一個數據模板叫HierarchicalDataTemplate,這個模板專門用於有頭部和子數據的數據結構的,用在這個TreeView中剛好合適。
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TreeViewDemo"> <HierarchicalDataTemplate DataType="{x:Type local:FriendList}" ItemsSource="{Binding Path=Friends,UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" x:Key="ListTemple" > <Border x:Name="bord" Margin="-1,-1,0,-1"> <TextBlock Text="{Binding Path=ListName, Mode=TwoWay}" HorizontalAlignment="Left" Width="227" Padding="2" FontSize="15"></TextBlock> </Border> </HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="{x:Type local:Friend}" x:Key="FriendTemple"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="40"></ColumnDefinition> <ColumnDefinition Width="150"></ColumnDefinition> </Grid.ColumnDefinitions> <Image Source="{Binding Path=HeadPath}" ></Image> <StackPanel Orientation="Horizontal" Grid.Column="1" Margin="6,2,2,2"> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Path=Name}" Height="25" HorizontalAlignment="Left" ></TextBlock> <TextBlock Text="{Binding Path=Autograph}" Height="20" HorizontalAlignment="Left"></TextBlock> </StackPanel> </StackPanel> </Grid> </HierarchicalDataTemplate> </ResourceDictionary>
(注意:因為需要再這里引用自定義類,所以命名空間local的引入一定要正確,沖上面的定義可以看出,好友列表只顯示名字,好友就用Grid來組織一個類QQ的布局,頭像,簽名等。)
五:主界面。
主界面比較簡單,在這個Demo中,只使用TreeView控件。
<Window x:Class="TreeViewDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TreeViewDemo" Title="MainWindow" Height="401" Width="305"> <Grid> <TreeView x:Name="ListTV" ></TreeView> </Grid> </Window>
六:有了軀殼,我們填入靈魂(數據綁定和數據模板應用)。
模板有兩個,直接填充TreeView的ItemTemplate屬性是不行的,但是WPF中有一個思想很重要(Selector、Converter等),在TreeView中有一個屬性ItemTemplateSelector。所以,新建一個Selector類,繼承DataTemplateSelector:
class FriendOrListTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { ResourceDictionary directory = new ResourceDictionary(); directory.Source = new Uri("pack://Application:,,,/GlobeDictionary.xaml", UriKind.RelativeOrAbsolute);//使用pack uri載入模板字典 if (item != null && item is FriendList) { return directory["ListTemple"] as DataTemplate; } return directory["FriendTemple"] as DataTemplate; } }
首先使用pack uri加載位於當前exe程序集中的字典資源(如果加載不了,請將字典生成方式改為Resource),然后根據傳入的數據類型來返回對應的DataTemplate,這樣就能有效的自動選擇模板。
模板能自動選擇了,另外數據怎么提供呢,我們使用在WPF中最常用的DataContext綁定來填充ItemsSource。下面看主界面的完整代碼。
<Window x:Class="TreeViewDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TreeViewDemo" Title="MainWindow" Height="401" Width="305"> <Grid> <Grid.Resources> <local:FriendOrListTemplateSelector x:Key="Myselector"></local:FriendOrListTemplateSelector> </Grid.Resources> <TreeView x:Name="ListTV" ItemsSource="{Binding Path=DataContext, Mode=TwoWay,RelativeSource={RelativeSource Mode=Self}}" ItemTemplateSelector="{StaticResource Myselector}" > </TreeView> </Grid> </Window>
這里的命名空間local是FriendOrListTemplateSelector所在的命名空間中,請填寫對。最后在主界面的代碼中加入數據,測試一下。
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); ObservableCollection<FriendList> Root = new ObservableCollection<FriendList>(); FriendList listOne = new FriendList("高中同學"); Friend friend1 = new Friend(listOne) { Autograph = "今天很開心,遇到了XX", HeadPath = "Heads/h1.png", Name = "天煞" }; Friend friend2 = new Friend(listOne) { Autograph = "非一般的感覺", HeadPath = "Heads/h2.png", Name = "Basx" }; Friend friend3 = new Friend(listOne) { Autograph = "WER", HeadPath = "Heads/h3.png", Name = "Paul" }; Friend friend4 = new Friend(listOne) { Autograph = "~終於完成作業了~~!", HeadPath = "Heads/h4.png", Name = "孤星月" }; listOne.AddFriend(friend1); listOne.AddFriend(friend2); listOne.AddFriend(friend3); listOne.AddFriend(friend4); FriendList listTwo = new FriendList("大一"); Friend friend5 = new Friend(listOne) { Autograph = "你的存在", HeadPath = "Heads/h5.png", Name = "菲菲" }; listTwo.AddFriend(friend5); Root.Add(listOne); Root.Add(listTwo); this.ListTV.DataContext = Root; } }
大功告成~!
總結
過程比較簡單,但是最重要的是學習其方法,有幾點通用的知識需要注意的:
1.Xaml中需要使用自定義類的時候,需要在頭部xmlns中添加一項,並且確保命名空間是對的。
2.Pack URI的使用,任何資源的引用都可以使用Pack URI,下面舉兩個例子:
*pack://Application:,,,/路徑/路徑/文件名(帶后綴) <-這種方式是引用當前程序集的Resouce資源的。
*pack://Application:,,,/引用的程序集名稱;component/路徑/路徑/文件名(帶后綴)<-這種方式是引用其他程序集的Resouce資源的。
3.選擇器(Selecter),轉換器(Converter)等的思想要深入理解。
4.數據模板是為數據定制外觀,例如這里就為Friend和FriendList定制了外觀了。
