簡體   English   中英

如何為每個TreeViewItem設置事件?

[英]How to set event for every TreeViewItem?

我想為我在代碼中動態創建的每個TreeViewItem設置一個事件。 我正在使用以下XAML代碼:

<Window.Resources>
        <Style TargetType="TreeViewItem">
            <EventSetter Event="Selected" Handler="TreeViewItemSelectionEvent"/>
            <EventSetter Event="MouseRightButtonDown" Handler="TreeViewItemRightClickEvent"/>
        </Style>
</Window.Resources>

但這僅適用於TreeView中的根TreeViewItem。 如果我單擊另一個項目,它是根的子級,那么我總是返回根。

我可以以某種方式進行這項工作嗎? 我很喜歡這種方法,因此您無需處理代碼中的事件,從而使它看起來更干凈。

TL; DR:使用HierarchicalDataTemplate和樣式在TreeView中顯示數據。 在視圖模型中動態加載數據將自動更新TreeView。

不要手動創建TreeViewItems。

在MVVM中,最重要的是數據和數據的體系結構。 通常的模式是定義數據,並分別定義視圖如何顯示數據。 您的視圖取決於數據,而不是相反。

因此,讓我們創建一個ProductViewModel ,它具有一個ProductName ,一個子產品列表和一個IsSelected屬性。 我們為此類配備了方法LoadSubProductsCollectionFromDataSource ,該方法可從您可能擁有的任何數據源中檢索數據。 在這里,我只加載一些虛擬物品。

public class ProductViewModel {
    /// <summary>
    /// Backing field for the IsSelected property
    /// </summary>
    private bool _isSelected;

    /// <summary>
    /// Gets or sets the collection of materials used to build this Product.
    /// </summary>
    public ObservableCollection<ProductViewModel> SubProducts { get; set; } = new ObservableCollection<ProductViewModel>();

    /// <summary>
    /// Gets or sets the name of this product.
    /// </summary>
    public string ProductName { get; set; }

    /// <summary>
    /// Gets or sets the selected state of this product.
    /// </summary>
    public bool IsSelected {
        get => _isSelected;
        set {
            //The product has been selected or deselected.
            if (!_isSelected && SubProducts.Count == 0) {
                //We load data into it if not already done.
                LoadSubProductsCollectionFromDataSource();
            }
            _isSelected = value;
        }
    }

    /// <summary>
    /// Loads sub products data into this product.
    /// </summary>
    private void LoadSubProductsCollectionFromDataSource() {
        //..
        //Do stuff to retrieve your data dynamically and
        //add them to the SubProducts collection.
        //...
        for (int i = 0; i < 5; i++) {
            //Add dummy items
            SubProducts.Add(new ProductViewModel() { ProductName = "Some product " + i.ToString() });
        }
    }
}

在您的MainWindow.xaml.cs中,初始化並公開如下所示的視圖模型對象的集合:

public partial class MainWindow : Window {
    /// <summary>
    /// Exposes the root product of the tree
    /// </summary>
    public ObservableCollection<ProductViewModel> RootProducts { get; } = new ObservableCollection<ProductViewModel>();

    public MainWindow() {
        InitializeComponent();
        RootProducts.Add(new ProductViewModel() { ProductName = "Root product" });
    }
}

該集合通常將存儲在主viewmodel對象中,但為簡單起見,我只是在MainWindow中創建了它。 請注意,我是如何將其作為屬性(允許綁定)和ObservableCollection(在集合更改時自動通知視圖)公開的。

最后,告訴您的視圖如何使用TreeView顯示ProductViewModel對象:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        x:Name="window"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <!--Tell the treeview how to hierarchically display and organize ProductViewModel items-->
        <HierarchicalDataTemplate DataType="{x:Type local:ProductViewModel}" ItemsSource="{Binding SubProducts}">
            <TextBlock Text="{Binding ProductName}"></TextBlock>
        </HierarchicalDataTemplate>
        <!--Tell each treeviewitem to bind IsSelected to the PoductViewModel.ISSelected property.-->
        <Style TargetType="TreeViewItem">
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"></Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <TreeView ItemsSource="{Binding ElementName=window, Path=RootProducts}"/>
    </Grid>
</Window>

現在,每次在TreeViewItem中選擇TreeView ,其IsSelected屬性都設置為true(這是TreeViewItem的行為)。 由於我們的綁定,它還將相應ProductViewModelIsSelected屬性設置為true。 在此屬性的設置器中,我們進行了調用以填充子產品列表。 因為此列表實際上是一個ObservableCollection ,所以它通知View( TreeView ),后者知道應該使用新的TreeViewItems更新自身。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM