如何在ItemsSource =自定义对象集合时选择/展开TreeView节点?

时间:2015-03-26 19:28:33

标签: c# wpf data-binding treeview hierarchicaldatatemplate

我有TreeView打算在两个级别上操作。对于他我有两个HierarchicalDataTemplate和两个自定义类型。 ItemsSourceObservableCollection相关联,一切正常。我无法想象如何从代码隐藏中选择或扩展节点。在某处提到了将IsExpandedIsSelected属性绑定到自定义类型中的相应属性的非常好的想法。唯一的问题是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 个答案:

答案 0 :(得分:7)

您可以尝试按以下方式更改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并出现在层次结构中的每个项目都需要具有这些属性。

答案 1 :(得分:1)

  

唯一的问题是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;

答案 2 :(得分:0)

我没有看到任何问题。您可以制作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);
    }
}

在drop handler中:

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 { /* ... */ } }
}