1. 程式人生 > >WPF TreeView IsExpanded 繫結不上的問題

WPF TreeView IsExpanded 繫結不上的問題

最近專案上需要通過MVVM來控制TreeView,其中需要需要控制通過搜尋來定位某個節點,正常邏輯下,首先通過需要在樹上面找到該節點,然後選中該節點,並將該節點的父節點展開,這個時候需要通過MVVM來控制,需要繫結起來,只是一直沒有binding上,程式碼如下:

MVVM示例程式碼:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Collections.ObjectModel;
  4 using System.Linq;
  5 using System.Text;
  6 using
System.Threading.Tasks; 7 8 namespace DragDrop 9 { 10 class DataItem : NotifyPropertyBase, ICloneable 11 { 12 public DataItem(string header, int deepth = 1) 13 { 14 Header = header; 15 Deepth = deepth; 16 } 17 18 public
object Clone() 19 { 20 DataItem dataItem = new DataItem(Header, Deepth); 21 dataItem.IsExpanded = IsExpanded; 22 dataItem.IsSelected = IsSelected; 23 dataItem.Deepth = Deepth; 24 foreach (DataItem item in Items) 25 dataItem.Items.Add((DataItem)item.Clone());
26 return dataItem; 27 } 28 29 private string header; 30 public string Header 31 { 32 get { return header; } 33 set 34 { 35 SetProperty(ref header, value); 36 } 37 } 38 39 private bool isSelected; 40 public bool IsSelected 41 { 42 get { return isSelected; } 43 set { SetProperty(ref isSelected, value); } 44 } 45 46 private bool isExpanded; 47 public bool IsExpanded 48 { 49 get { return isExpanded; } 50 set 51 { 52 SetProperty(ref isExpanded, value); 53 Console.WriteLine("{0}--{1}", Header, IsExpanded); 54 } 55 } 56 57 private int deepth; 58 public int Deepth 59 { 60 get { return deepth; } 61 set 62 { 63 if (deepth != value) 64 { 65 deepth = value; 66 SetProperty(ref deepth, value); 67 } 68 } 69 } 70 71 private ObservableCollection<DataItem> mItems = null; 72 public ObservableCollection<DataItem> Items 73 { 74 get 75 { 76 if (mItems == null) 77 mItems = new ObservableCollection<DataItem>(); 78 return mItems; 79 } 80 } 81 82 } 83 84 class Data 85 { 86 private static Data mInstance = new Data(); 87 88 public static Data Instance 89 { 90 get { return mInstance; } 91 } 92 93 private ObservableCollection<DataItem> GenerateTreeViewItems() 94 { 95 ObservableCollection<DataItem> items = new ObservableCollection<DataItem>(); 96 97 DataItem item1 = new DataItem("TreeViewItem1"); 98 item1.Items.Add(new DataItem("SubItem1", item1.Deepth)); 99 item1.Items.Add(new DataItem("SubItem2", item1.Deepth)); 100 item1.Items.Add(new DataItem("SubItem3", item1.Deepth)); 101 item1.Items.Add(new DataItem("SubItem4", item1.Deepth)); 102 items.Add(item1); 103 104 DataItem item2 = new DataItem("TreeViewItem2"); 105 item2.Items.Add(new DataItem("SubItem1", item2.Deepth)); 106 item2.Items.Add(new DataItem("SubItem2", item2.Deepth)); 107 items.Add(item2); 108 109 DataItem item3 = new DataItem("TreeViewItem3"); 110 item3.Items.Add(new DataItem("SubItem1", item3.Deepth)); 111 item3.Items.Add(new DataItem("SubItem2", item3.Deepth)); 112 item3.Items.Add(new DataItem("SubItem3", item3.Deepth)); 113 item3.Items.Add(new DataItem("SubItem4", item3.Deepth)); 114 item3.Items.Add(new DataItem("SubItem5", item3.Deepth)); 115 item3.Items.Add(new DataItem("SubItem6", item3.Deepth)); 116 item3.Items.Add(new DataItem("SubItem7", item3.Deepth)); 117 item3.Items.Add(new DataItem("SubItem8", item3.Deepth)); 118 items.Add(item3); 119 120 return items; 121 } 122 123 private ObservableCollection<DataItem> GenerateListItems() 124 { 125 ObservableCollection<DataItem> items = new ObservableCollection<DataItem>(); 126 items.Add(new DataItem("ListBoxItem1")); 127 items.Add(new DataItem("ListBoxItem2")); 128 items.Add(new DataItem("ListBoxItem3")); 129 items.Add(new DataItem("ListBoxItem4")); 130 items.Add(new DataItem("ListBoxItem5")); 131 return items; 132 } 133 134 public ObservableCollection<DataItem> TreeViewItems 135 { 136 get 137 { 138 if (mTreeViewItems == null) 139 mTreeViewItems = GenerateTreeViewItems(); 140 return mTreeViewItems; 141 } 142 } 143 144 public ObservableCollection<DataItem> ListBoxItems 145 { 146 get 147 { 148 if (mListBoxItems == null) 149 mListBoxItems = GenerateListItems(); 150 return mListBoxItems; 151 } 152 } 153 154 private ObservableCollection<DataItem> mTreeViewItems = null; 155 private ObservableCollection<DataItem> mListBoxItems = null; 156 } 157 }

介面程式碼:

 1 <Window x:Class="DragDrop.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:DragDrop"
 7         mc:Ignorable="d"
 8         Title="MainWindow" Height="350" Width="525">
 9     <Window.Resources>
10         <HierarchicalDataTemplate x:Key="treeViewTemplate" DataType="{x:Type local:DataItem}" ItemsSource="{Binding Items}">
11             <TextBlock Text="{Binding Header}"/>
12         </HierarchicalDataTemplate>
13 
14         <Style x:Key="TreeViewStyle" TargetType="{x:Type TreeViewItem}">
15             <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
16             <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
17             <Style.Triggers>
18                 <DataTrigger Binding="{Binding Deepth}" Value="1">
19                     <Setter Property="IsExpanded" Value="True"/>
20                 </DataTrigger>
21             </Style.Triggers>
22         </Style>
23     </Window.Resources>
24     <Grid x:Name="mTopLevelGrid">
25         <TreeView x:Name="mTreeView" Grid.Column="0"
26                   ItemsSource="{Binding Source={x:Static local:Data.Instance}, Path=TreeViewItems}"
27                   ItemTemplate="{StaticResource treeViewTemplate}"
28                   ItemContainerStyle="{StaticResource TreeViewStyle}"/>
29     </Grid>
30 </Window>

資料的繫結沒有問題,介面沒有問題,奇怪的是IsSelected可以正常繫結,但是IsExpanded就是不行,後來發現這兩個屬性唯一的區別就是在TreeView的式樣中

1 <Style.Triggers>
2      <DataTrigger Binding="{Binding Deepth}" Value="1">
3            <Setter Property="IsExpanded" Value="True"/>
4       </DataTrigger>
5 </Style.Triggers>

後面把這個DataTrigger這段程式碼註釋掉,編譯一下,重新執行,IsExpanded就可以正常繫結。後面自己思考了一下,MVVM模式實現將ViewModel與介面上面的顯示繫結起來,實際上也就是使用了觀察者模式,而Trigger的原理應該和資料binding是一樣的,而且這個Trigger寫在後面,可能直接把前面的繫結取代了,但是試了一下,將DataTrigger放到前面,也還是繫結不上,這種可能性排除;個人猜測可能是Trigger的優先順序比較高,從而造成IsExpanded一直Binding不上去。