WPF/Silverlight HierarchicalDataTemplate 模版的使用


上一篇 對Wpf/Silverlight Template 進行了總結,本篇繼續上一篇,主要是介紹 HierarchicalDataTemplate 的使用方法。HierarchicalDataTemplate 繼承於DataTemplate,被稱之為"層級式數據模板",主要是應用層級比較明顯數據集合,其典型的應用就是對TreeView控件進行數據綁定,接下來就在Silverlight 5 下進行一下演示。最近有個賣涼茶的節目比較火,叫中國好聲音,里面的導師和其歌手的分組就是個層級結構,我們暫且先用它來做個例子吧。

首先我們需要准備一下層級的數據集合,定義一個歌手類:

歌手類
    /// <summary>
    /// 歌手類
    /// </summary>
    public class Singer
    {
        /// <summary>
        /// 歌手編號
        /// </summary>
        public int SingerId { get; set; }

        /// <summary>
        /// 歌手名稱
        /// </summary>
        public string SingerName { get; set; }

        /// <summary>
        /// 歌手頭像
        /// </summary>
        public string SingerHeader { get; set; }
    }

 然后定義一個 導師類,導師類中有個屬性就是歌手的集合,代碼如下:

導師類
    /// <summary>
    /// 導師類
    /// </summary>
    public class Teacher
    {
        /// <summary>
        /// 導師編號
        /// </summary>
        public int TeacherId { get; set; }

        /// <summary>
        /// 導師名稱
        /// </summary>
        public string TeacherName { get; set; }

        /// <summary>
        /// 導師頭像
        /// </summary>
        public string TeacherHeader { get; set; }

        /// <summary>
        /// 學生列表
        /// </summary>
        public ObservableCollection<Singer> SingerList { get; set; }
    }

 接下來用代碼組織一個導師與歌手的層級數據集合:

好聲音層級數據集合
    /// <summary>
    /// 好聲音數據集合
    /// </summary>
    public class GoodVoice
    {
        public static ObservableCollection<Teacher> GoodVoiceData;

        static GoodVoice()
        {
            GoodVoiceData = new ObservableCollection<Teacher>();
            GoodVoiceData.Add(new Teacher()
            {
                TeacherId = 1,
                TeacherName = "劉歡",
                TeacherHeader = @"Images/劉歡/劉歡.png",
                SingerList = new ObservableCollection<Singer>()
                {
                   new Singer(){ SingerId=1, SingerName="吉克雋逸",SingerHeader=@"Images/劉歡/吉克雋逸.png"},
                   new Singer(){ SingerId=2, SingerName="權振東",SingerHeader=@"Images/劉歡/權振東.png"},
                   new Singer(){ SingerId=3, SingerName="徐海星",SingerHeader=@"Images/劉歡/徐海星.png"},
                   new Singer(){ SingerId=4, SingerName="袁婭維",SingerHeader=@"Images/劉歡/袁婭維.png"},
                }
            });

            GoodVoiceData.Add(new Teacher()
            {
                TeacherId = 2,
                TeacherName = "那英",
                TeacherHeader = @"Images/那英/那英.png",
                SingerList = new ObservableCollection<Singer>()
                {
                   new Singer(){ SingerId=5, SingerName="張煒",SingerHeader=@"Images/那英/張煒.png"},
                   new Singer(){ SingerId=6, SingerName="梁博",SingerHeader=@"Images/那英/梁博.png"},
                   new Singer(){ SingerId=7, SingerName="張赫宣",SingerHeader=@"Images/那英/張赫宣.png"},
                   new Singer(){ SingerId=8, SingerName="多亮",SingerHeader=@"Images/那英/多亮.png"},
                }
            });

            GoodVoiceData.Add(new Teacher()
            {
                TeacherId = 3,
                TeacherName = "楊坤",
                TeacherHeader = @"Images/楊坤/楊坤.png",
                SingerList = new ObservableCollection<Singer>()
                {
                   new Singer(){ SingerId=9, SingerName="金志文",SingerHeader=@"Images/楊坤/金志文.png"},
                   new Singer(){ SingerId=10, SingerName="關喆",SingerHeader=@"Images/楊坤/關喆.png"},
                   new Singer(){ SingerId=11, SingerName="平安",SingerHeader=@"Images/楊坤/平安.png"},
                   new Singer(){ SingerId=12, SingerName="丁丁",SingerHeader=@"Images/楊坤/丁丁.png"},
                }
            });

            GoodVoiceData.Add(new Teacher()
            {
                TeacherId = 4,
                TeacherName = "庾澄慶",
                TeacherHeader = @"Images/庾澄慶/庾澄慶.png",
                SingerList = new ObservableCollection<Singer>()
                {
                   new Singer(){ SingerId=9, SingerName="金池",SingerHeader=@"Images/庾澄慶/金池.png"},
                   new Singer(){ SingerId=10, SingerName="王韻壹",SingerHeader=@"Images/庾澄慶/王韻壹.png"},
                   new Singer(){ SingerId=11, SingerName="吳莫愁",SingerHeader=@"Images/庾澄慶/吳莫愁.png"},
                   new Singer(){ SingerId=12, SingerName="大山",SingerHeader=@"Images/庾澄慶/大山.png"},
                }
            });
        }
    }

 有了數據集合,我們就可以在Xaml中編寫我們的 HierarchicalDataTemplate 模版了,我們定義兩個模版,一個TeacherTemplate 代表導師節點,一個SingerTemplate 代表歌手節點,並把TeacherTemplate中的ItemTemplate指定為SingerTemplate,具體代碼如下: 

<common:HierarchicalDataTemplate x:Key="SingerTemplate">        
        <StackPanel Orientation="Horizontal" Height="24">
            <Image Source="{Binding SingerHeader}" Height="24" Width="24"/>
            <TextBlock Text="{Binding SingerName}" Margin="2,0,0,0" VerticalAlignment="Center" FontSize="12" Foreground="Green" />           
        </StackPanel>
</common:HierarchicalDataTemplate>
    
<common:HierarchicalDataTemplate x:Key="TeacherTemplate" ItemsSource="{Binding SingerList}" ItemTemplate="{StaticResource SingerTemplate}">
        <StackPanel Orientation="Horizontal" Height="24">
            <Image Source="{Binding TeacherHeader}" Height="24" Width="24" />
            <TextBlock Text="{Binding TeacherName}" Margin="2,0,0,0" HorizontalAlignment="Center"  FontSize="14" Foreground="Blue"/>
        </StackPanel>
</common:HierarchicalDataTemplate>

 在Silverlight下,需要在Xaml代碼中添加如下命名空間:xmlns:common="clr-namespace:System.Windows;assembly=System.Windows.Controls" 

在此之后,在主界面MainPage.xaml 中添加一個TreeView控件,並給該控件增加一個根節點,命名為 RootItem,並把該根節點的ItemTemplate指定為我們剛剛編寫的層級模版中的 TeacherTemplate:

<sdk:TreeView x:Name="GoodVoiceTree" Width="200" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch">
    <sdk:TreeViewItem x:Name="RootItem" ItemTemplate="{StaticResource TeacherTemplate}" IsExpanded="True">
         <sdk:TreeViewItem.HeaderTemplate>
              <DataTemplate>
                 <StackPanel Orientation="Horizontal">
                    <Image Source="images/中國好聲音.png" Height="24" Width="24"/>
                    <TextBlock Text="中國好聲音" Margin="2,0,0,0" VerticalAlignment="Center" FontSize="16" Foreground="Red" />
                 </StackPanel>
              </DataTemplate>
         </sdk:TreeViewItem.HeaderTemplate>
   </sdk:TreeViewItem>
</sdk:TreeView>

 接下來,我們為該樹控件的根節點RootItem綁定我們的數據集合就可以展現我們的樹形控件了:

this.RootItem.ItemsSource = GoodVoice.GoodVoiceData;

 運行結果如下圖:

其實在我們的實際開發項目中有些數據的層級結構是固定的,比如上面的例子,就固定了導師和歌手兩個層級,固定的層級的話我們可以對每一層的樣式方便的進行控制(直接在每層的模版中制作就可以)。但還有很多的時候,數據的層級是不固定的,我們也來進行一下簡單的演示:

首先定義個TreeNode類,代表每層的數據模型:

TreeNode 代碼
    public class TreeNode
    {
        /// <summary>
        /// 節點名稱
        /// </summary>
        public string  NodeName { get; set; }

        /// <summary>
        /// 節點圖片
        /// </summary>
        public string NodeImage { get; set; }

        /// <summary>
        /// 是否展開
        /// </summary>
        public bool IsOpen { get; set; }

        /// <summary>
        /// 子節點
        /// </summary>
        public ObservableCollection<TreeNode> ChildNode { get; set; }
    }

 同樣用代碼組織一個層級數據集合:

TreeNodeData
    public class TreeNodeData
    {
        public static ObservableCollection<TreeNode> TreeNodeList;
        
        static TreeNodeData()
        {
            TreeNodeList = new ObservableCollection<TreeNode>();
            //根節點
            TreeNode RootNode = new TreeNode()
            {
                NodeName = "根節點",
                NodeImage = @"Images/Tree/Root.png",
                IsOpen = true,
                ChildNode = new ObservableCollection<TreeNode>()               
            };

            //子節點A
            TreeNode Node_A = new TreeNode()
            {
                NodeName = "子節點A",
                NodeImage = @"Images/Tree/Node.png",
                IsOpen = false,
                ChildNode = new ObservableCollection<TreeNode>()
            };
            Node_A.ChildNode.Add(new TreeNode() { NodeName = "葉子節點A-1", NodeImage = @"Images/Tree/Leaf.png", IsOpen = false });
            Node_A.ChildNode.Add(new TreeNode() { NodeName = "葉子節點A-2", NodeImage = @"Images/Tree/Leaf.png", IsOpen = false });
            Node_A.ChildNode.Add(new TreeNode() { NodeName = "葉子節點A-3", NodeImage = @"Images/Tree/Leaf.png", IsOpen = false });
            
            //子節點B
            TreeNode Node_B = new TreeNode()
            {
                NodeName = "子節點B",
                NodeImage = @"Images/Tree/Node.png",
                IsOpen = true,
                ChildNode = new ObservableCollection<TreeNode>()
            };
            Node_B.ChildNode.Add(new TreeNode() { NodeName = "葉子節點B-1", NodeImage = @"Images/Tree/Leaf.png", IsOpen = false });
            Node_B.ChildNode.Add(new TreeNode() { NodeName = "葉子節點B-2", NodeImage = @"Images/Tree/Leaf.png", IsOpen = false });

            //節點B 子節點B-3
            TreeNode Node_B_3 = new TreeNode()
            {
                NodeName = "子節點B-3",
                NodeImage = @"Images/Tree/SubNode.png",
                IsOpen = false,
                ChildNode = new ObservableCollection<TreeNode>()
            };
            Node_B_3.ChildNode.Add(new TreeNode() { NodeName = "葉子節點B-3-1", NodeImage = @"Images/Tree/Leaf.png", IsOpen = false });
            Node_B_3.ChildNode.Add(new TreeNode() { NodeName = "葉子節點B-3-2", NodeImage = @"Images/Tree/Leaf.png", IsOpen = false });

            Node_B.ChildNode.Add(Node_B_3);         
            RootNode.ChildNode.Add(Node_A);
            RootNode.ChildNode.Add(Node_B);

            TreeNodeList.Add(RootNode);
            
        }
    }

在Xaml中編寫的層級模版:

<common:HierarchicalDataTemplate x:Key="TreeNodeTemplate" ItemsSource="{Binding ChildNode}" >
    <StackPanel Orientation="Horizontal" Height="24">
        <Image Source="{Binding NodeImage}" Height="24" Width="24" />
        <TextBlock Text="{Binding NodeName}" Margin="2,0,0,0" HorizontalAlignment="Center"  FontSize="12" Foreground="Blue"/>
    </StackPanel>
</common:HierarchicalDataTemplate>

在這里我們需要注意一個問題:我們在TreeNode類的時候定義個一個布爾值屬性 IsOpen,就是利用這個屬性來控制我們這棵樹的節點的展開閉合狀態的:True 代表該節點展開,False 代表該節點閉合。如果不這么做我們對 TreeView控件進行綁定后,樹的初始狀態都是閉合的,但是這種方法僅限於WPF 和 Silverlight 5 ,Silverlight4 及以下版本是不靈滴,不知道是不是Silverlight的一個Bug。

<sdk:TreeView x:Name="MyTree" Width="200" Grid.Row="1" Grid.Column="1"  ItemTemplate="{StaticResource TreeNodeTemplate}"            
                      HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch">
        <sdk:TreeView.ItemContainerStyle>
            <Style TargetType="sdk:TreeViewItem">
                 <Setter Property="IsExpanded" Value="{Binding IsOpen}"/>
            </Style>
        </sdk:TreeView.ItemContainerStyle>           
</sdk:TreeView>

 這里我們就利用了上一篇提到的TreeView的ItemContainerStyle屬性,對TreeView中的所有TreeviewItem的IsExpander屬性進行了綁定。

同樣將我們的數據集合綁定到我們的這個TreeView控件上: 

this.MyTree.ItemsSource = TreeNodeData.TreeNodeList;

 由於我們在數據集合中對 根節點 和 子節點B 的IsOpen屬性設置為了True,因此這兩個節點是展開的,運行結果如下圖:

至此,在Silverlight下利用HierarchicalDataTemplate 層級模版綁定TreeView控件的使用方式,演示完畢,至於如何獲取TreeView 節點的數據,我們可以在TreeView控件中的SelectedItemChanged事件中進行獲取,這里就不貼代碼了,大家可以下載源碼參看。

源碼下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM