潛移默化學會WPF(難點控件treeview)--改造TreeView(CheckBox多選擇版本),遞歸綁定數據


目前自己對treeview的感慨很多

今天先講 面對這種 表結構的數據 的其中一種綁定方法,后面多幾列其他屬性都沒關系,例如多個字段,

1  A  0

2  B  0

3  C  0

4  D  1

5  E  2

6  F  4

7  G 1

...

就是遞歸型的表結構

然后通過treeview 展示( treeview 的name 叫 tv , collection 是 ObservableCollection<T> 的 一個實例

1.首先你必須需要  要建立一個 跟treeview 結構很相似的一個集合,這里建議用  ObservableCollection<T>   這個集合很特殊,你要記得,例如 tv.ItemsSource = this.collection;  當你這樣綁定時,修改collection的屬性時就是修改treeview綁定的某些屬性

 

2.在做綁定時一定要 搞清楚treeview的item的結構,你想呈現什么樣的,每個 treeveiwItem就是一個對象 ,這個對象可以用一個類去替代,或者什么去替代

 

3. 不啰嗦了,說正題,新建一個實體類

例如

   

   /// <summary>
   ////// </summary>
   public class ReportCategoryEntity
   {
       /// <summary>
       /// ID
       /// </summary>
       public int Id { get; set; }
       /// <summary>
       /// 名稱
       /// </summary>
       public string Title { get; set; }
       /// <summary>
       ///父節點
       /// </summary>
       public int ParentID { get; set; }


   }

 

這個應該看得懂吧,加入那個遞歸表 叫 FoodCatagory(菜品目錄) 表,現在只要遞歸顯示出來就行了

把他所有行取出來 select * from FoodCatagory,如果其中不止基本的三列,有其他列,例如通過這些列的值  作為控制 treeview顯示的樣式的條件用 這也是很不錯的點子,真的,比如說再加一個圖片的地址,如果有個圖片地址字典表,這里就存那個表中的字段了,如果其他字段你需要,那你可以繼續寫在 ReportCategoryEntity 這個類中

 

讀出來的所有行封裝到  List<ReportCategoryEntity>    lstReportCategoryEntity  ,這個應該會把,如果不會,說明你的oop基礎沒學好了

 

好了

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Media;

namespace 命名空間
{
    public class TreeCategory : INotifyPropertyChanged
    {
        private ObservableCollection<TreeCategory> children = new ObservableCollection<TreeCategory>();

        public TreeCategory() { }

        public TreeCategory(List<ReportCategoryEntity> totalCategory, int parentID)  //0  根目錄
        {
            //Parent = this;
            foreach (ReportCategoryEntity item in totalCategory)
            {
                if (item.ParentID == parentID)
                {
                    TreeCategory tc = new TreeCategory(totalCategory, item.Id);
                    tc.Title = item.Title;
                    children.Add(tc);
                }
            }
        }

        public ObservableCollection<TreeCategory> Children
        {
            get { return this.children; }
        }

        /// <summary>
        /// 顯示的名稱
        /// </summary>
        private string title;
        public string Title
        {
            get
            {
                return title;
            }
            set
            {
                title = value;
                this.NotifyPropertyChanged("Title");
            }
        }
        /// <summary>
        /// 是否選中
        /// </summary>
        private bool isSelected = false;
        public bool IsSelected
        {
            set
            {
                this.isSelected = value;
                this.NotifyPropertyChanged("IsSelected");
            }
            get { return this.isSelected; }
        }

        /// <summary>
        /// 標題字體顏色
        /// </summary>
        private Brush foregroundBrush = new SolidColorBrush(Colors.Black);
        public Brush ForegroundBrush
        {
            set
            {
                this.foregroundBrush = value;
                this.NotifyPropertyChanged("ForegroundBrush");
            }
            get { return this.foregroundBrush; }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }


    }
}

 

 

接下來再建立一個最重要的 類,用來控制treeview顯示的,看似像實體類,但又不像,下面是我建立的,本類下有個本類的集合的屬性,還是ObservableCollection集合的,加了 INotifyPropertyChanged 只是為了達到只要修改這個集合的某些屬性的值,就可以修改treeview的狀態了。

例如我這里添加了 標題字體顏色  ForegroundBrush  這個屬性,就是為了達到treeview的每個節點的顯示顏色,你在遞歸的時候就可以根據 ReportCategoryEntity 的某些屬性作為條件,然后動態給ForegroundBrush  賦值,要記住,每一個 TreeCategory 類就已經對應了一個 treeviewItem,該類的每一個字段都可以作為 treeview 顯示出來的條件,至於前面treeview的樣式模板該怎么寫,很快你就清楚了

 

現在說一下 xaml 中前台的寫法

 <TreeView Name="tv" Width="170" Height="800" MaxHeight="520" BorderThickness="0">
                    <TreeView.ItemContainerStyle>
                        <Style TargetType="TreeViewItem">
                            <Setter Property="TreeViewItem.IsExpanded" Value="True"/>
                            <!--<Setter Property="TreeViewItem.IsSelected" Value="{Binding IsSelected}"/>-->
                            <!--<EventSetter Event="MouseMove" Handler="tree_MouseMove" />-->
                            <!--<EventSetter Event="KeyDown" Handler="treeViewItem_KeyDown" />-->
                            <Setter Property="TreeViewItem.Margin" Value="0,1,0,0"/>
                        </Style>
                    </TreeView.ItemContainerStyle>
                    <TreeView.ItemTemplate>
                        <HierarchicalDataTemplate DataType="{x:Type c:TreeCategory}"  ItemsSource="{Binding Children}">
                            <StackPanel  Margin="-2,0,0,0" Orientation="Horizontal" x:Name="staTree">
                                <CheckBox Content="{Binding Title}" FontSize="14" FontFamily="微軟雅黑" Tag="{Binding Children}" IsChecked="{Binding IsSelected}" Foreground="{Binding ForegroundBrush}" Unchecked="ck_Unchecked" Checked="ck_Checked"></CheckBox>
                            </StackPanel>
                            <HierarchicalDataTemplate.Triggers>
                                <DataTrigger Binding="{Binding IsSelected}" Value="true">
                                    <Setter TargetName="staTree" Property="Background" Value="White"/>
                                </DataTrigger>
                            </HierarchicalDataTemplate.Triggers>
                        </HierarchicalDataTemplate>
                    </TreeView.ItemTemplate>

                </TreeView>

重點看  <TreeView.ItemTemplate>  這個節點下面的 ,<TreeView.ItemContainerStyle>用來控制總體顯示樣式的

 

現在你應該有點清楚了

 

1. 首先你要知道  treeviewItem 對應一個  TreeCategory ,treeview控件每個節點下都有可能有子節點,像一個集合,所以我在TreeCategory 類中又包括了他自己的一個集合,已達到構造出和treeview很像的一個結構,感覺到了嗎

2. ReportCategoryEntity  這個實體是  把從數據庫讀出來的每條數據的一個net樣子,一條表中的數據對應一個 ReportCategoryEntity  實體對象,達到封裝效果,不一定只有這三個字段,拓展他以達到treeview顯示更豐富的效果,而且treeview的模板很好寫,可以改造出很多種

3.就是 TreeCategory 類  ,如果以前沒有接觸xaml語言的可能會有疑問  

public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

為什么會有這堆代碼,而且每個屬性后面,又調了這個 NotifyPropertyChanged 方法,我不知道原理,但我知道怎么用了,wpf的控件很奇特,不像winform控件或者 asp.net控件那么死,重寫個控件很難,這就是為什么wpf 做的桌面軟件五花八門,而且很炫,只要你的到控件,不脫離實際,控件都可以變成你想要的控件。又說了好多廢話。

最重要的還是我的那個 遞歸

 public TreeCategory(List<ReportCategoryEntity> totalCategory, int parentID)  //0  根目錄
        {
            //Parent = this;
            foreach (ReportCategoryEntity item in totalCategory)
            {
                if (item.ParentID == parentID)
                {
                    TreeCategory tc = new TreeCategory(totalCategory, item.Id);
//加一些你想要的字段,然后在這里賦值吧 tc.Title
= item.Title; children.Add(tc); } } }

 

4.為了達到treeview顯示的不同效果,加了數據觸發器,這樣后台一行代碼也不要寫,有必要的話,你可以再加一個值轉換器吧 ,加一些你想要的數據觸發器吧,豐富顯示效果,例如根據某個字段作為判斷條件,如果是什么,把image 控件的source地址換了,就可以達到不同的節點,顯示不同的圖片了  ,具體應用有很多

<HierarchicalDataTemplate.Triggers>
                                <DataTrigger Binding="{Binding IsSelected}" Value="true">
                                    <Setter TargetName="staTree" Property="Background" Value="White"/>
                                </DataTrigger>
 //加一些你想要的數據觸發器吧,豐富顯示效果,例如根據某個字段作為判斷條件,如果是什么,把image 控件的source地址換了,就可以達到不同的節點,顯示不同的圖片了  
</HierarchicalDataTemplate.Triggers>

 

 

后台綁定

    private ObservableCollection<TreeCategory> collection = new ObservableCollection<TreeCategory>();

     this.collection = new TreeCategory(ctagr, 0).Children;
                treeCategories.ItemsSource = this.collection;
ctagr 是個List<ReportCategoryEntity> 集合

 

先冒個泡

這是我做的一個菜品目錄checkbox多選版本的 ,作為導航欄的,例如選中這個目錄,列出這個目錄下的所有菜,或者計算出這個菜品目錄的菜的銷售情況等等,擴展一下,部門與員工是挺經典的一個例子

 

至於選中根節點,子節點全部選中,那你可以寫在checkbox的事件里,應該會吧,這我就不寫了,建議遞歸吧,應為你不知道他下面有多少個子節點

 

這個我加了checkbox選擇的模式,全選,全不選,反選,隨選

這個我就再說一點吧,然后來體現ObservableCollection 集合的好處

你不可能修改treeviewItem的屬性吧,那個有點傻了

直接修改ObservableCollection 中的 TreeCategory 的IsSelected屬性就行了,treeview中自動體現

這里我就只說個全選,全不選 的吧

下面是我寫的一個算法

為了防止你粘貼復制,不思考我就上個圖吧

反選應該就不用我說了吧,留着思考吧

而且每個 節點的 checkbox都是可以改的,而且你還可以組合控件,例如把很多控件放在stackpanel 中,作為一個treeviewItem

例如每個節點鼠標移上去的效果你都可以很輕松的改的,就看你的技術了,鼠標移上去,我就不說了

再看個圖吧

如果你熟悉treeview的話,迅雷看看的這個目錄效果很輕松的可以做出來,那個TreeviewItem加載動畫也可以做

,這是個 目錄下有具體內容的treeview結構,這個如果也用這種MVVM思想的話也可以很輕松的做出來,我做過,多態做的,呵呵,下次有時間的話就再寫篇 treeview下面有內容時,該怎么寫。

 

我自己感覺迅雷看看有點像 Expander 加 treeview  控件呢?下次做一個迅雷看看左邊的目錄 制作教程吧,好了,就暫時啰嗦到這里吧

 

 

 

 

 

 

 

 

 

 

 


免責聲明!

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



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