【问题标题】:WPF ListBox TreeViewItem to Fill Width of TreeViewWPF ListBox TreeViewItem 填充 TreeView 的宽度
【发布时间】:2014-05-07 04:08:49
【问题描述】:

如果我有一个使用 ListBox 控件作为 TreeViewItems 的 TreeView,如何让 ListBoxItems 跨越整个 TreeView 容器。

 <Grid>
    <TreeView>
        <TreeViewItem Header="General 1">
            <ListBox BorderThickness="0">
                <ListBoxItem>Item A</ListBoxItem>
                <ListBoxItem>Item B</ListBoxItem>
                <ListBoxItem>Item C</ListBoxItem>
            </ListBox>
        </TreeViewItem>
        <TreeViewItem Header="General 2">
            <ListBox BorderThickness="0">
                <ListBoxItem>Item A</ListBoxItem>
                <ListBoxItem>Item B</ListBoxItem>
                <ListBoxItem>Item C</ListBoxItem>
            </ListBox>
        </TreeViewItem>
        <TreeViewItem Header="General 3">
            <ListBox BorderThickness="0">
                <ListBoxItem>Item A</ListBoxItem>
                <ListBoxItem>Item B</ListBoxItem>
                <ListBoxItem>Item C</ListBoxItem>
            </ListBox>
        </TreeViewItem>
        <TreeViewItem Header="General 4">
            <ListBox BorderThickness="0">
                <ListBoxItem>Item A</ListBoxItem>
                <ListBoxItem>Item B</ListBoxItem>
                <ListBoxItem>Item C</ListBoxItem>
            </ListBox>
        </TreeViewItem>
    </TreeView>
</Grid>

这会产生如下图所示的结果。请注意,选定的 ListBoxItem 不跨越 Treeview 控件的宽度。

【问题讨论】:

    标签: c# wpf listbox treeview listboxitem


    【解决方案1】:

    默认情况下,TreeViewItems 的行为方式与您现在的行为方式相同,因此ListBox 与它无关。 TreeViewItem 只是用ContentPresenter 包围你的ListBox。为了让它跨越选定的项目高亮画笔需要额外的工作。

    您有多种选择,可以将Template 修改为TreeViewItem

    <ControlTemplate TargetType="{x:Type TreeViewItem}">
    <StackPanel>
        <Border Name="Bd"
          Background="{TemplateBinding Background}"
          BorderBrush="{TemplateBinding BorderBrush}"
          BorderThickness="{TemplateBinding BorderThickness}"
          Padding="{TemplateBinding Padding}">
            <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="19" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
                  <ToggleButton x:Name="Expander"
                          Style="{StaticResource ExpandCollapseToggleStyle}"
                          IsChecked="{Binding Path=IsExpanded,
                                      RelativeSource={RelativeSource TemplatedParent}}"
                          ClickMode="Press"/>
                  <ContentPresenter x:Name="PART_Header"
                        Grid.Column="1"
                            ContentSource="Header"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
            </Grid>
      </Border>
      <ItemsPresenter x:Name="ItemsHost" Margin="19,0,0,0" />
    </StackPanel>
    <!-- Triggers -->
    </ControlTemplate>
    

    这个问题是它不会跨越到ToggleButton。它只会跨越第二列项目。其中ExpandCollapseToggleStyle可以到实控模板中提取。

    即使包含切换按钮,它也会跨越的另一个解决方案是使用长度转换器和 TreeViewItem 扩展方法来获取深度。这两者都与 TreeViewItem 可视化树紧密耦合,因此如果您开始弄乱模板,那么您可能会遇到麻烦。

    定义样式

    完整的 TreeViewItem 样式

    <SolidColorBrush x:Key="GlyphBrush" Color="#444" />
    <Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
      <Setter Property="Focusable" Value="False"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="ToggleButton">
            <Grid
              Width="15"
              Height="13"
              Background="Transparent">
              <Path x:Name="ExpandPath"
                HorizontalAlignment="Left" 
                VerticalAlignment="Center" 
                Margin="1,1,1,1"
                Fill="{StaticResource GlyphBrush}"
                Data="M 4 0 L 8 4 L 4 8 Z"/>
            </Grid>
            <ControlTemplate.Triggers>
              <Trigger Property="IsChecked"
                   Value="True">
                <Setter Property="Data"
                    TargetName="ExpandPath"
                    Value="M 0 4 L 8 4 L 4 8 Z"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    <Style x:Key="TreeViewItemFocusVisual">
      <Setter Property="Control.Template">
        <Setter.Value>
          <ControlTemplate>
            <Border>
              <Rectangle Margin="0,0,0,0"
                     StrokeThickness="5"
                     Stroke="Black"
                     StrokeDashArray="1 2"
                     Opacity="0"/>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    
    
    <Style x:Key="{x:Type TreeViewItem}"
         TargetType="{x:Type TreeViewItem}">
      <Setter Property="Background"
          Value="Transparent"/>
      <Setter Property="HorizontalContentAlignment"
          Value="{Binding Path=HorizontalContentAlignment,
                  RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
      <Setter Property="VerticalContentAlignment"
          Value="{Binding Path=VerticalContentAlignment,
                  RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
      <Setter Property="Padding"
          Value="1,0,0,0"/>
      <Setter Property="Foreground"
          Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
      <Setter Property="FocusVisualStyle"
          Value="{StaticResource TreeViewItemFocusVisual}"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type TreeViewItem}">
            <ControlTemplate.Resources>
                <local:LeftMarginMultiplierConverter Length="19" x:Key="lengthConverter" />
            </ControlTemplate.Resources>
            <StackPanel>
            <Border Name="Bd"
                  Background="{TemplateBinding Background}"
                  BorderBrush="{TemplateBinding BorderBrush}"
                  BorderThickness="{TemplateBinding BorderThickness}"
                  Padding="{TemplateBinding Padding}">
                <Grid Margin="{Binding Converter={StaticResource lengthConverter},
                                  RelativeSource={RelativeSource TemplatedParent}}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="19" />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
              <ToggleButton x:Name="Expander"
                      Style="{StaticResource ExpandCollapseToggleStyle}"
                      IsChecked="{Binding Path=IsExpanded,
                                  RelativeSource={RelativeSource TemplatedParent}}"
                      ClickMode="Press"/>
    
                <ContentPresenter x:Name="PART_Header"
                Grid.Column="1"
                          ContentSource="Header"
                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
                </Grid>
              </Border>
              <ItemsPresenter x:Name="ItemsHost" />
            </StackPanel>
            <ControlTemplate.Triggers>
              <Trigger Property="IsExpanded"
                   Value="false">
                <Setter TargetName="ItemsHost"
                    Property="Visibility"
                    Value="Collapsed"/>
              </Trigger>
              <Trigger Property="HasItems"
                   Value="false">
                <Setter TargetName="Expander"
                    Property="Visibility"
                    Value="Hidden"/>
              </Trigger>
              <MultiTrigger>
                <MultiTrigger.Conditions>
                  <Condition Property="HasHeader"
                         Value="false"/>
                  <Condition Property="Width"
                         Value="Auto"/>
                </MultiTrigger.Conditions>
                <Setter TargetName="PART_Header"
                    Property="MinWidth"
                    Value="75"/>
              </MultiTrigger>
              <MultiTrigger>
                <MultiTrigger.Conditions>
                  <Condition Property="HasHeader"
                         Value="false"/>
                  <Condition Property="Height"
                         Value="Auto"/>
                </MultiTrigger.Conditions>
                <Setter TargetName="PART_Header"
                    Property="MinHeight"
                    Value="19"/>
              </MultiTrigger>
              <Trigger Property="IsSelected"
                   Value="true">
                <Setter TargetName="Bd"
                    Property="Background"
                    Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                <Setter Property="Foreground"
                    Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
              </Trigger>
              <MultiTrigger>
                <MultiTrigger.Conditions>
                  <Condition Property="IsSelected"
                         Value="true"/>
                  <Condition Property="IsSelectionActive"
                         Value="false"/>
                </MultiTrigger.Conditions>
                <Setter TargetName="Bd"
                    Property="Background"
                    Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                <Setter Property="Foreground"
                    Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
              </MultiTrigger>
              <Trigger Property="IsEnabled"
                   Value="false">
                <Setter Property="Foreground"
                    Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
    

                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="19" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <ToggleButton x:Name="Expander"
                        Style="{StaticResource ExpandCollapseToggleStyle}"
                        IsChecked="{Binding Path=IsExpanded,
                        RelativeSource={RelativeSource TemplatedParent}}"
                        ClickMode="Press"/>
    
                    <ContentPresenter x:Name="PART_Header"
                        Grid.Column="1"
                        ContentSource="Header"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
                </Grid>
          </Border>
          <ItemsPresenter x:Name="ItemsHost" />
        </StackPanel>
        <!-- Triggers -->
    </ControlTemplate>
    

    TreeViewDepth 扩展

    public static class TreeViewItemExtensions
    {
        public static int GetDepth(this TreeViewItem item)
        {
            TreeViewItem parent;
            while ((parent = GetParent(item)) != null)
            {
                return GetDepth(parent) + 1;
            }
            return 0;
        }
    
        private static TreeViewItem GetParent(TreeViewItem item)
        {
            var parent = VisualTreeHelper.GetParent(item);
            while (!(parent is TreeViewItem || parent is TreeView))
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
            return parent as TreeViewItem;
        }
    }
    

    LeftMarginMultiplierConverter

    public class LeftMarginMultiplierConverter : IValueConverter
    {
        public double Length { get; set; }
    
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var item = value as TreeViewItem;
            if (item == null)
                return new Thickness(0);
    
            return new Thickness(Length * item.GetDepth(), 0, 0, 0);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
    

    控制

    <TreeView Margin="50">
    
        <TreeViewItem Header="General 1">
            <ListBox BorderThickness="0">
                <ListBoxItem>Item A</ListBoxItem>
                <ListBoxItem>Item B</ListBoxItem>
                <ListBoxItem>Item C</ListBoxItem>
            </ListBox>
        </TreeViewItem>
        <TreeViewItem Header="General 2">
            <ListBox BorderThickness="0">
                <ListBoxItem>Item A</ListBoxItem>
                <ListBoxItem>Item B</ListBoxItem>
                <ListBoxItem>Item C</ListBoxItem>
            </ListBox>
        </TreeViewItem>
        <TreeViewItem Header="General 3">
            <ListBox BorderThickness="0">
                <ListBoxItem>Item A</ListBoxItem>
                <ListBoxItem>Item B</ListBoxItem>
                <ListBoxItem>Item C</ListBoxItem>
            </ListBox>
        </TreeViewItem>
        <TreeViewItem Header="General 4">
            <ListBox BorderThickness="0">
                <ListBoxItem>Item A</ListBoxItem>
                <ListBoxItem>Item B</ListBoxItem>
                <ListBoxItem>Item C</ListBoxItem>
            </ListBox>
        </TreeViewItem>
    </TreeView>
    

    【讨论】:

      【解决方案2】:

      尝试将此style 应用到您的 TreeView,

        <Style TargetType="TreeViewItem">
              <Setter Property="Template">
                  <Setter.Value>
                      <ControlTemplate TargetType="TreeViewItem">
                          <StackPanel>
                              <VisualStateManager.VisualStateGroups>
                                  <VisualStateGroup x:Name="ExpansionStates">
                                      <VisualState x:Name="Expanded">
                                          <Storyboard>
                                              <ObjectAnimationUsingKeyFrames
                                          Storyboard.TargetProperty="(UIElement.Visibility)"
                                          Storyboard.TargetName="ItemsHost">
                                                  <DiscreteObjectKeyFrame KeyTime="0"
                                              Value="{x:Static Visibility.Visible}" />
                                              </ObjectAnimationUsingKeyFrames>
                                          </Storyboard>
                                      </VisualState>
                                      <VisualState x:Name="Collapsed" />
                                  </VisualStateGroup>
                              </VisualStateManager.VisualStateGroups>
                              <ContentPresenter ContentSource="Header" />
                              <ItemsPresenter Name="ItemsHost" Visibility="Collapsed" />
                          </StackPanel>
                      </ControlTemplate>
                  </Setter.Value>
              </Setter>
          </Style>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-04-27
        • 2012-09-29
        • 2018-04-25
        • 1970-01-01
        • 1970-01-01
        • 2017-05-25
        • 1970-01-01
        相关资源
        最近更新 更多