为 TreeViewItem 使用自定义样式时,Wpf 树视图双向绑定不起作用

Wpf tree-view two-way binding not working when using custom style for TreeViewItem

我尝试设置一个自定义样式的树视图,它通过将展开的 属性 双向绑定到视图模型中的类似 属性 来 "just in time" 加载。样式和功能方面单独使用时效果很好,但放在一起时就不行了。

当我这样做时,功能就在那里:

<TreeView Name="treeView" ItemsSource="{Binding}" Grid.Column="0">
    <TreeView.Resources>
        <ResourceDictionary  Source="GroupedTreeViewItemStyle.xaml"/>
    </TreeView.Resources>

    <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
            <Setter Property="IsExpanded"  Value="{Binding Expanded, Mode=TwoWay}"/>
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

但是当我添加 BasedOn 以使用我的自定义样式时,它不再加载任何节点。 我通过将上面的样式定义替换为以下内容来使用我的样式:

<Style TargetType="TreeViewItem" BasedOn="{StaticResource GroupedTreeViewItemStyle}">

这是我根据 this 教程自定义的样式:

<ResourceDictionary  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:this="*******namespace omitted*******">

<!-- This Style redefines the ControlTemplate used by TreeViewItems and
   also provides a different itemspanel for their child items. -->
<Style TargetType="TreeViewItem" x:Key="GroupedTreeViewItemStyle">
    <Style.Resources>
        <LinearGradientBrush x:Key="ItemAreaBrush" StartPoint="0.5, 0" EndPoint="0.5, 1" Opacity="1">
            <GradientStop Color="#fff" Offset="0" />
            <GradientStop Color="#f2fcfe" Offset="1" />
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="SelectedItemAreaBrush" StartPoint="0.5, 0" EndPoint="0.5, 1" Opacity="1">
            <GradientStop Color="#fff" Offset="0" />
            <GradientStop Color="#f2fcfe" Offset="1" />
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="ItemBorderBrush" StartPoint="0.5, 0" EndPoint="0.5, 1">
            <GradientStop Color="#243B55" Offset="0" />
            <GradientStop Color="#141E30" Offset="1" />
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="SelectedItemBorderBrush" StartPoint="0.5, 0" EndPoint="0.5, 1">
            <GradientStop Color="#243B55" Offset="0" />
            <GradientStop Color="#141E30" Offset="1" />
        </LinearGradientBrush>

        <DropShadowBitmapEffect x:Key="DropShadowEffect" />
    </Style.Resources>



    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="TreeViewItem">
                <Grid Margin="8,4">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>

                    <!-- This Border contains elements which display 
             the content and child items of the TreeViewItem. -->
                    <Border Name="Bd" 
          Background="{StaticResource ItemAreaBrush}"
          BorderBrush="{StaticResource ItemBorderBrush}" 
          BorderThickness="0.6" 
          CornerRadius="8"              
          Padding="6"     
          SnapsToDevicePixels="True"
          >
                        <Grid>
                            <!-- Items with children are 
                 shown in an Expander. -->
                            <Expander Name="Exp" IsExpanded="{TemplateBinding TreeViewItem.IsExpanded}">
                                <Expander.Header>
                                    <!-- Displays the item's header in the Expander. -->
                                    <ContentPresenter ContentSource="Header" />
                                </Expander.Header>
                                <!-- Displays the item's children. -->
                                <ItemsPresenter />
                            </Expander>

                            <!-- Items without children are 
                 shown in a ContentPresenter. -->
                            <ContentPresenter Name="CntPres"
              ContentSource="Header"
              HorizontalAlignment="Center"
              VerticalAlignment="Center"
              Visibility="Collapsed" 
              />
                        </Grid>
                    </Border>
                </Grid>

                <ControlTemplate.Triggers>
                    <!-- If the TreeViewItem has child items,
             show it in an Expander.  Otherwise
             hide the Expander and show the hidden
             ContentPresenter. -->
                    <Trigger Property="TreeViewItem.HasItems" Value="false">
                        <Setter 
            TargetName="Exp" 
            Property="Visibility" 
            Value="Collapsed" />
                        <Setter 
            TargetName="CntPres" 
            Property="Visibility" 
            Value="Visible" />
                    </Trigger>

                    <!--When the item is selected in the TreeView, use the 
            "selected" colors and give it a drop shadow. -->
                    <Trigger Property="IsSelected" Value="true">
                        <Setter
            TargetName="Bd"
            Property="Panel.Background"                     
            Value="{StaticResource SelectedItemAreaBrush}" />
                        <Setter
            TargetName="Bd"
            Property="Border.BorderBrush"                     
            Value="{StaticResource SelectedItemBorderBrush}" />
                        <!--<Setter
            TargetName="Bd"
            Property="TextElement.Foreground"                   
            Value="{DynamicResource 
              {x:Static SystemColors.HighlightTextBrushKey}}" />-->
                        <Setter
            TargetName="Bd"
            Property="Border.BitmapEffect"                  
            Value="{StaticResource DropShadowEffect}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <!-- Make each TreeViewItem show it's children 
     in a StackPanel. If it is a root item then
     the Orientation will be 'Horizontal', else
     'Vertical'. -->
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <ItemsPanelTemplate.Resources>
                    <this:ItemsPanelOrientationConverter x:Key="conv" />
                </ItemsPanelTemplate.Resources>
                <StackPanel 
        IsItemsHost="True" 
        Orientation="{Binding 
          RelativeSource={x:Static RelativeSource.TemplatedParent}, 
          Converter={StaticResource conv}}" 
        />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>


</Style>

有人知道我在结合我的树的样式和功能时做错了什么吗? 问题是样式已经根据 isExpanded 属性 定义了什么?还是缺少某些东西,类似于 super(isExpanded)?

感谢您的帮助!

扩展器绑定可能是问题的原因:

<Expander Name="Exp" IsExpanded="{TemplateBinding TreeViewItem.IsExpanded}">

根据documentation,

A TemplateBinding is always a one-way binding, even if properties involved default to two-way binding.

(另见 TemplateBinding limitations

尝试re-write绑定为:

<Expander Name="Exp" 
          IsExpanded="{Binding IsExpanded, 
                               RelativeSource={RelativeSource TemplatedParent}}">