在所选项目上访问可观察集合中的项目

本文关键字:项目 集合 观察 访问 选项 | 更新日期: 2023-09-27 18:34:50

我有一个 WPF 树视图,该视图由使用层次结构数据绑定的可观察集合填充我需要访问可观察集合中的项目或用于填充它的数据库。一个示例用例是用户右键单击树视图项以添加子组。我显然需要访问其父级来添加子项。有什么建议吗?我太迷茫了..

我不能只编辑树视图项目本身,因为更改不会反映回我的数据库

数据库代码:

[Serializable]
public class LoginGroup
{
    public string Name { get; set; }
    public Guid ID { get; set; }
    public List<Login> LoginItems = new List<Login>();
    public List<LoginGroup> Children { get; set; }
}
public static ObservableCollection<LoginGroup> _GroupCollection = new  ObservableCollection<LoginGroup>();
public ObservableCollection<LoginGroup> GroupCollection
{
    get { return _GroupCollection; }
}

树视图:

<TreeView x:Name="groupView" Width="211" TreeViewItem.Selected="OnTreeItemSelected" DockPanel.Dock="Left" Height="Auto" ItemsSource="{Binding GroupCollection}" >
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Path=Children}">
            <TextBlock Text="{Binding Path=Name}" />
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

在所选项目上访问可观察集合中的项目

您可以将SelectedItem转换为LoginGroup

LoginGroup selectedGroup = (LoginGroup)groupView.SelectedItem;

您无法反映属性的更改,因为它们无法"注意到"它们已被编辑。您需要从DependencyObject继承LoginGroup或实现INotifyPropertyChanged

您应该使用 TreeView 的 ItemContainer 样式。
下面是示例 TreeNode 视图模型:

public class TreeNode : ViewModel
{
    public TreeNode()
    {
        this.children = new ObservableCollection<TreeNode>();
        // the magic goes here
        this.addChildCommand = new RelayCommand(obj => AddNewChild());
    }
    private void AddNewChild()
    {
        // create new child instance
        var child = new TreeNode 
        { 
            Name = "This is a new child node.",
            IsSelected = true // new child should be selected
        };
        // add it to collection
        children.Add(child);
        // expand this node, we want to look at the new child node
        IsExpanded = true;
    }
    public String Name
    {
        get { return name; }
        set
        {
            if (name != value)
            {
                name = value;
                OnPropertyChanged("Name");
            }
        }
    }
    private String name;
    public Boolean IsSelected
    {
        get { return isSelected; }
        set
        {
            if (isSelected != value)
            {
                isSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }
    }
    private Boolean isSelected;
    public Boolean IsExpanded
    {
        get { return isExpanded; }
        set
        {
            if (isExpanded != value)
            {
                isExpanded = value;
                OnPropertyChanged("IsExpanded");
            }
        }
    }
    private Boolean isExpanded;
    public ObservableCollection<TreeNode> Children
    {
        get { return children; } 
    }
    private ObservableCollection<TreeNode> children;
    public ICommand AddChildCommand
    {
        get { return addChildCommand; }
    }
    private RelayCommand addChildCommand;
}

一些评论:

  • ViewModel 是 INotifyPropertyChanged 的任何基本实现接口。
  • RelayCommand(又名DelegateCommand(是用于MVVM方法的ICommand实现。

这是视图:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <TreeView ItemsSource="{Binding}">
        <TreeView.ItemContainerStyle>
            <!-- Let's glue our view models with the view! -->
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu>
                            <!-- Here's menu item, which is responsible for adding new child node -->
                            <MenuItem Header="Add child..." Command="{Binding AddChildCommand}" />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>
            </Style>
        </TreeView.ItemContainerStyle>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                <TextBlock Text="{Binding Name}"/>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</Window>

。和示例数据上下文初始化:

    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ObservableCollection<TreeNode>
        {
            new TreeNode { Name = "Root", IsSelected = true }
        };
    }

希望这有帮助。

更新
当然,您还必须将子节点公开为 ObservableCollection。否则,将不会反映对节点集合所做的更改。