WPF之Treeview實現MVVM雙向綁定


Treeview分別有兩個數據模板HierarchicalDataTemplate(層級數據模板)和DataTemplate(數據模板),分別應用於生成子數據項和普通數據項。
在使用過程中,如果對兩個模板的DataType設置為同一類型,運行時會直接報錯。

大概原因是添加了倆個相同Key的資源(因為HierarchicalDataTemplateDataTemplate都是定義在<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一般都是數據庫取出來的數據處理嵌套后的結果。有時候會遇到需求,對於不同的分類有不同的類型。根據雙向綁定的規則,我們只需要修改ViewModelTypeList的內容就可以了。

注意: ObservableCollection只有在列表項發生變化時才會觸發頁面刷新,即新增或刪除時才會反應到頁面上。若采用直接賦值的寫法,不會觸發頁面刷新。

推薦更新數據時候的寫法:

 //清空原先的列表
TypeList.Clear();
list.ForEach(d =>
{
    TypeList.Add(d);
});

TreeView.SelectedItem雙向綁定

TreeView.SelectedItemReadOnly的,所以不能通過簡單的綁定方法去獲取選中項

最終還是要通過綁定TreeviewSelectedItemChanged事件,來修改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"
  • 綁定CommandSelectedItemChanged事件
<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;
            });
        }
    }
}

效果圖:

ViewModelBaseCommandBase是自己封裝的基類,就是為了寫WPF的雙向綁定簡單點,有興趣的可以評論向我要。
Demo地址: https://github.com/fxhui/TreeViewDemo


免責聲明!

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



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