当ItemsSource为自定义对象集合时,如何使TreeView节点被选中/展开?

5

我有一个TreeView,旨在操作两个级别。为此,我有两个HierarchicalDataTemplate和两个自定义类型。ItemsSource链接到ObservableCollection,一切正常。我只是不知道如何从codebehind使节点选定或展开。有人提出了一个非常好的想法,将IsExpanded和IsSelected属性绑定到我的自定义类型中相应的属性。唯一的问题是,HierarchicalDataTemplate没有直接实现TreeViewItem,那么我怎样才能在以下代码中访问这些属性呢?

<TreeView Name="treeViewNotes" AllowDrop="True" PreviewMouseLeftButtonDown="treeViewNotes_PreviewMouseLeftButtonDown" PreviewMouseMove="treeViewNotes_PreviewMouseMove" Drop="treeViewNotes_Drop" DragEnter="treeViewNotes_DragEnter">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type dataclasses:NoteFolder}" ItemsSource="{Binding Notes}">
            <StackPanel Orientation="Horizontal">
                <Image Height="16" Source="{Binding TreeViewIcon}" Tag="{Binding Self}"/>
                <TextBlock Text="{Binding Title}" Tag="{Binding Self}" Margin="3"/>
            </StackPanel>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type dataclasses:Note}">
            <StackPanel Orientation="Horizontal">
                <Image Height="16" Source="{Binding TreeViewIcon}" Tag="{Binding Self}"/>
                <TextBlock Text="{Binding Title}" Tag="{Binding Self}" Margin="3"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

我希望在创建并添加新的Note到某个NoteFolder时,能够选择此Note并展开Folder。在拖放操作上,同样需要进一步改善UI响应。

3个回答

9
您可以尝试按照以下方式更改TreeView的ItemContainerStyle,使其IsExpanded和IsSelected属性绑定到DataContext的IsExpanded和IsSelected属性:
<TreeView x:Name="..." ItemsSource="{Binding RootNode}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <!-- Items in the ItemsSource need to have these properties for the binding to work -->
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <!-- You can also optionally change some style values based on IsSelected and IsExpanded values -->
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsSelected}" Value="True">
                    <Setter Property="BorderThickness" Value="4 0 0 1"/>
                    <Setter Property="BorderBrush" Value="DeepSkyBlue"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsSelected}" Value="False">
                    <Setter Property="BorderThickness" Value="4 0 0 1 "/>
                    <Setter Property="BorderBrush" Value="Transparent"/>
                </DataTrigger>
            </Style.Triggers>
         </Style>
     </TreeView.ItemContainerStyle>
     <TreeView.Resources>
        <HierarchicalDataTemplate>
             ...
        </HierarchicalDataTemplate>
     </TreeView.Resources>
</TreeView>

当然,来自ItemSource并存在于层次结构中的每个项目都需要具有这些属性。

2
你的方法有效!我只想指出自定义对象必须实现 INotifyPropertyChanged - mandarin

3

唯一的问题是,HierarchicalDataTemplate 没有直接实现 TreeViewItem,那么我该如何在以下代码中访问这些属性呢?

您可以在 TreeView.ItemContainerStyle 中实现:

<TreeView ItemTemplate="{StaticResource ResourceKey=treeViewDataTemplate}"
      ItemsSource="{Binding Data}"
      Name="trvTreeView">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsSelected" Value="{Binding Path=IsSelected}" />
            <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded}" />
            <EventSetter Event="Expanded" Handler="TreeViewItem_Expanded" />
            <EventSetter Event="Collapsed" Handler="TreeViewItem_Collapsed" />
            <EventSetter Event="PreviewMouseRightButtonDown" Handler="TreeViewItem_PreviewMouseRightButtonDown" />
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

在代码后台:
private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
{
    TreeViewItem treeViewItem = e.OriginalSource as TreeViewItem;
    if (treeViewItem != null)
    {
        BaseObjectExplorerNode baseObjectExplorerNode = treeViewItem.Header as BaseObjectExplorerNode;
        if (baseObjectExplorerNode != null)
        {
            baseObjectExplorerNode.IsExpanded = true;
        }
    }
}

private void TreeViewItem_Collapsed(object sender, RoutedEventArgs e)
{
    TreeViewItem treeViewItem = e.OriginalSource as TreeViewItem;
    if (treeViewItem != null)
    {
        BaseObjectExplorerNode baseObjectExplorerNode = treeViewItem.Header as BaseObjectExplorerNode;
        if (baseObjectExplorerNode != null)
        {
            baseObjectExplorerNode.IsExpanded = false;
        }
    }
}

然后例如:

root.IsExpanded = true;

1
我可以帮您进行翻译。这段内容是关于编程的,作者认为没有问题。您可以创建一个StyleSelector,两个Style并将其绑定到属性。
XAML:
<TreeView Name="treeViewNotes" AllowDrop="True" PreviewMouseLeftButtonDown="treeViewNotes_PreviewMouseLeftButtonDown" PreviewMouseMove="treeViewNotes_PreviewMouseMove" Drop="treeViewNotes_Drop" DragEnter="treeViewNotes_DragEnter">
    <TreeView.Resources>
        <!-- StyleSelector for containers -->
        <notdataclasses:NoteStyleSelector x:Key="NoteStyleSelector" />

        <!-- Style for a NoteFolder's container -->
        <Style x:Key="NoteFolderStyle" TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsSelected" Value="{Binding Path=IsSelected}" />
            <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded}" />
            <Setter Property="ItemContainerStyleSelector" Value="{StaticResource NoteFolderStyle}" />
        </Style>
        <!-- Style for a Note's container -->
        <Style x:Key="NoteStyle" TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsSelected" Value="{Binding Path=IsSelected}" />
        </Style>

        <!-- ... -->
    </TreeView.Resources>
    <TreeView.ItemContainerStyleSelector>
        <StaticResource ResourceKey="NoteStyleSelector" />
    </TreeView.ItemContainerStyleSelector>
</TreeView>

NoteStyleSelector:
public sealed class NoteStyleSelector : StyleSelector
{
    public override Style SelectStyle(object item, DependencyObject container)
    {
        FrameworkElement fe = container as FrameworkElement;

        if (fe!= null)
        {
            if (item is Note)
            { return (Style)fe.FindResource("NoteStyle"); }

            if (item is NoteFolder)
            { return (Style)fe.FindResource("NoteFolderStyle"); }
        }

        return base.SelectStyle(item, container);
    }
}

在一个拖放处理程序中:
currentFolder.Nodes.Add(pastedNode);

currentFolder.IsExpanded = true;
currentNode.IsSelected = true;

数据类型:
public class Note : INotifyPropertyChanged
{
    // Only the IsSelected property because a Note can not be expanded
    public bool IsSelected { get { /* ... */ } set { /* ... */ } }
}

public class NoteFolder : INotifyPropertyChanged
{
    public bool IsSelected { get { /* ... */ } set { /* ... */ } }
    public bool IsExpanded { get { /* ... */ } set { /* ... */ } }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接