Treeview
分別有兩個數據模板HierarchicalDataTemplate
(層級數據模板)和DataTemplate
(數據模板),分別應用於生成子數據項和普通數據項。
在使用過程中,如果對兩個模板的DataType
設置為同一類型,運行時會直接報錯。
大概原因是添加了倆個相同Key的資源(因為HierarchicalDataTemplate
和DataTemplate
都是定義在<TreeView.Resources>
標簽中)。
代碼:
public class TypeTreeModel :TypeModel
{
public ObservableCollection<TypeTreeModel> ChildList { get; set; }
= new ObservableCollection<TypeTreeModel>();
}
public class TypeModel
{
public int Id { get; set; }
public string Name { get; set; }
}
<TreeView x:Name="treeView" ItemsSource="{Binding TypeList}" MinWidth="200" MaxHeight="200" >
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type vm:TypeTreeModel}" ItemsSource="{Binding ChildList}">
<TextBlock Text="{Binding Name}" Margin="3 2"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type vm:TypeModel}">
<TextBlock Text="{Binding Name}" ToolTip="{Binding Id}" Margin="3 2"></TextBlock>
</DataTemplate>
</TreeView.Resources>
</TreeView>
效果圖:
TypeList
一般都是數據庫取出來的數據處理嵌套后的結果。有時候會遇到需求,對於不同的分類有不同的類型。根據雙向綁定的規則,我們只需要修改ViewModel
中TypeList
的內容就可以了。
注意: ObservableCollection
只有在列表項發生變化時才會觸發頁面刷新,即新增或刪除時才會反應到頁面上。若采用直接賦值的寫法,不會觸發頁面刷新。
推薦更新數據時候的寫法:
//清空原先的列表
TypeList.Clear();
list.ForEach(d =>
{
TypeList.Add(d);
});
TreeView.SelectedItem雙向綁定
TreeView.SelectedItem
是ReadOnly
的,所以不能通過簡單的綁定方法去獲取選中項
最終還是要通過綁定Treeview
的SelectedItemChanged
事件,來修改ViewModel
中的數據
1.直接綁定事件
<TreeView ItemsSource="{Binding TypeList}" SelectedItemChanged="TreeView_OnSelectedItemChanged" />
private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
vm.SelectItem = (Cluster)e.NewValue;
}
2.通過Command
綁定事件
- 在項目中引用
System.Windows.Interactivity.WPF
(簡單來說該插件可以將頁面控件的Event
轉為ViewModel中的Command
) - 在窗體中添加引用
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
- 綁定
Command
到SelectedItemChanged
事件
<TreeView x:Name="treeView" ItemsSource="{Binding TypeList}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectedItemChanged">
<i:InvokeCommandAction Command="{Binding SelectItemChangeCommand}"
CommandParameter="{Binding ElementName=treeView,Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
ViewModel:
public class TreeViewModel : ViewModelBase
{
public ObservableCollection<TypeTreeModel> TypeList;
private TypeModel selectItem;
public TypeModel SelectItem
{
get { return selectItem; }
set { this.MutateVerbose(ref selectItem, value, RaisePropertyChanged()); }
}
public TreeViewModel()
{
TypeList = GetData();
}
public ICommand SelectItemChangeCommand
{
get
{
return new CommandBase((param) =>
{
if(param != null)
SelectItem = (TypeModel)param;
});
}
}
}
效果圖:
ViewModelBase
和CommandBase
是自己封裝的基類,就是為了寫WPF的雙向綁定簡單點,有興趣的可以評論向我要。
Demo地址: https://github.com/fxhui/TreeViewDemo