整行的WPF树视图项目背景

Posted

技术标签:

【中文标题】整行的WPF树视图项目背景【英文标题】:WPF treeview item background over entire row 【发布时间】:2013-03-27 10:30:57 【问题描述】:

我正在编写一个应用程序,我需要在整行下逐项设置背景。我在here 中找到了一些灵​​感,但我不知道如何在模板中获取边框背景值(问题有点复杂:)

我的问题是树视图中有两种类型的“数据”(文件和文件夹)。用户可以修改文件和文件夹下的背景。

现在我在文本块上有背景,但它看起来很糟糕,我想在整个行上都有背景(我认为它看起来会更好)。

现在看来是这样:

但我需要的是:

如果我更改边框背景的值,我会更改所有项目(逻辑上)。所以我想我真的需要使用文本块背景,但我无法覆盖整个行(拉伸不是解决方案,因为它只是将它传播到行尾,而不是之前的那个空白)。

感谢您的建议。

编辑: XAML 在这里:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:treeView">
<!-- TREEVIEW  -->
    <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="Red"
            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 x: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 Grid.Column="1" x:Name="Expander"
                                  Style="StaticResource ExpandCollapseToggleStyle"
                                  IsChecked="Binding Path=IsExpanded,
                                              RelativeSource=RelativeSource TemplatedParent"
                                  ClickMode="Press"/>
                                <ContentPresenter x:Name="PART_Header" Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ContentSource="Header" />
                            </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>
</ResourceDictionary>

【问题讨论】:

你能写你的 XAML 代码吗? 【参考方案1】:

感谢您的解决方案!这是我到目前为止所做的预览:

<TreeView Grid.Row="1"  Name="treeView" Margin="5">
    <TreeView.ItemContainerStyle>
        <Style TargetType="x:Type TreeViewItem">
            <Setter Property="IsExpanded" Value="Binding IsExpanded, Mode=TwoWay" />
            <Setter Property="KeyboardNavigation.AcceptsReturn" Value="True" />
            <Setter Property="IsSelected" Value="Binding IsSelected, Mode=TwoWay" />
            <!-- Style for the selected item -->
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="x:Type TreeViewItem">
                        <ControlTemplate.Resources>
                            <Conv:LeftMarginMultiplierConverter Length="19" x:Key="lengthConverter" />
                        </ControlTemplate.Resources>
                        <StackPanel>
                            <Border 
                                x: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 
                                        Grid.Column="0" 
                                        x:Name="Expander"
                                        Style="StaticResource ExpandCollapseToggleStyle"
                                        IsChecked="Binding Path=IsExpanded, RelativeSource=RelativeSource TemplatedParent"
                                        ClickMode="Press"/>
                                    <ContentPresenter x:Name="PART_Header" Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ContentSource="Header" />
                                </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 TargetName="Bd" Property="Background" Value="#FFF7D280"/>
                                <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 TargetName="Bd" Property="Background" Value="#FFDADADA"/>
                                <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.Triggers>
                <!-- Selected and has focus -->
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="BorderBrush" Value="StaticResource HT_Background_Orange"/>
                </Trigger>
                <!-- Mouse over -->
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="#FFFDE8BA"/>
                    <!--<Setter Property="Background">
                        <Setter.Value>
                            <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                                <GradientStop Color="#FFFAFBFD" Offset="0"/>
                                <GradientStop Color="#fadfa3" Offset="1"/>
                            </LinearGradientBrush>
                        </Setter.Value>
                    </Setter>-->
                    <Setter Property="BorderBrush" Value="#f59246"/>
                </Trigger>
                <!-- Selected but does not have the focus -->
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsSelected" Value="True"/>
                        <Condition Property="IsSelectionActive" Value="False"/>
                    </MultiTrigger.Conditions>
                    <Setter Property="BorderBrush" Value="#f59246"/>
                </MultiTrigger>
            </Style.Triggers>
            <Style.Resources>
                <Style TargetType="Border">
                    <Setter Property="CornerRadius" Value="0"/>
                </Style>
            </Style.Resources>
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate DataType="x:Type local:FileSystemObjectInfo" ItemsSource="Binding Path=Children">
            <StackPanel Orientation="Horizontal">
                <Image
                    Source="Binding Path=ImageSource, UpdateSourceTrigger=PropertyChanged" 
                    Margin="0,1,8,1"
                    Height="24"
                    Width="24"/>
                <TextBlock
                    Text="Binding Path=FileSystemInfo.Name"
                    VerticalAlignment="Center"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
    <TreeView.Resources>

        <!-- Brushes for the selected item -->
        <LinearGradientBrush x:Key="x:Static SystemColors.HighlightBrushKey" EndPoint="0,1" StartPoint="0,0">
            <GradientStop Color="#FFFDF2DA" Offset="0"/>
            <GradientStop Color="#FFF7D280" Offset="1"/>
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="x:Static SystemColors.ControlBrushKey" EndPoint="0,1" StartPoint="0,0">
            <GradientStop Color="White" Offset="0"/>
            <GradientStop Color="#FFE2E2E2" Offset="1"/>
        </LinearGradientBrush>
        <SolidColorBrush x:Key="x:Static SystemColors.HighlightTextBrushKey" Color="Black" />
        <SolidColorBrush x:Key="x:Static SystemColors.ControlTextBrushKey" Color="Black" />
    </TreeView.Resources>
</TreeView>
public class LeftMarginMultiplierConverter : IValueConverter

    public double Length  get; set; 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        TreeViewItem 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();
    


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)
    
        DependencyObject parent = item != null ? VisualTreeHelper.GetParent(item) : null;
        while (parent != null && !(parent is TreeViewItem || parent is TreeView))
        
            parent = VisualTreeHelper.GetParent(parent);
        
        return parent as TreeViewItem;
    

<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>

如果您有任何问题,请告诉我!

问候

【讨论】:

酷!!!我正在寻找这个解决方案,但不完整,转换器和工具样式代码不存在,但谢谢。 我在帖子中添加了LeftMarginMultiplierConverterExpandCollapseToggleStyle 为我节省了大量时间!谢谢!【参考方案2】:

使用How to get children of a WPF container by type?中的GetChildOfType方法完成Dominic Jonas的解决方案:

public class LeftMarginMultiplierConverter : IValueConverter
    
        public int Length  get; set; 
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        
            Thickness thickness = new Thickness(0, 0, 0, 0);
            if (value != null)
            
                TreeViewItem treeViewItem = (TreeViewItem)value;
                ItemsControl parent = ItemsControl.ItemsControlFromItemContainer(treeViewItem);
                if (parent != null)
                
                    if (parent.GetType() == typeof(TreeView))
                    
                        thickness = new Thickness(System.Convert.ToDouble(Length), 5, 5, 5);
                    
                    else if (parent.GetType() == typeof(TreeViewItem))
                    
                        Grid grid = (Grid) Helper.GetChildOfType<Grid>(parent);
                        if(grid != null)
                            thickness = new Thickness(System.Convert.ToDouble(grid.Margin.Left + Length), 5, 5, 5);
                    
                
            
            return thickness;
        

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        
            throw new NotImplementedException();
        
    
    public static class Helper
    
        public static T GetChildOfType<T>(this DependencyObject depObj) where T : DependencyObject
        
            if (depObj == null) return null;

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            
                var child = VisualTreeHelper.GetChild(depObj, i);

                var result = (child as T) ?? GetChildOfType<T>(child);
                if (result != null) return result;
            
            return null;
        
    

并且仅在单行中突出显示鼠标:How can I make WPF Trigger for IsMouseOver on TreeViewItem NOT affect all parents of the moused-over control?

【讨论】:

【参考方案3】:

使用 snoop 了解您尝试修改的可视化树。这样,实际上需要 2-3 分钟才能知道您需要修改什么。 (谷歌)

我敢打赌,你需要使用这样的东西:

<TreeView>
<TreeView.ItemContainerStyle>
<Style BasedOn="StaticResource x:Type TreeViewItem" TargetType="TreeViewItem">
                    <Setter Property="Background" Value="Purple" />
</TreeView.ItemContainerStyle>
</TreeView>

如果你想要背景颜色取决于项目,你还需要添加触发器。

【讨论】:

这似乎是一个答案..让我更详细地检查一下..我很快就会把它标记为一个答案..thx! 它让我有些改变,但问题是,当我将 itemContainterStyle 放入代码中时,只有前几项是“紫色”.. @piggy 我不确定这是否可行。您可以将背景值绑定到您的视图模型吗?我还没有尝试过,所以不确定这是否有效。 @Faisal 背景我可以绑定。在 XAML 中,它是 TreeViewItem 中的第一个设置器。但这会绑定所有项目和子项目。 itemContainer 看起来可以工作,但问题是它将背景设置在项目的顶层:D aaaa 我讨厌模板..:/ ^^ ehm 好吧,我真的很愚蠢..:/..使用这个模板,它可以简单地设置树视图项的背景..:/(在 2 小时之前,我有另一个模板,哪里出了问题“并且背景更改根本不起作用..我重写了treeview的模板,现在可以使用..:/..)..好吧,给我减号,我的大坏^^,但SNOOP帮了我很多。 .thx thx,我的应用程序结束了..

以上是关于整行的WPF树视图项目背景的主要内容,如果未能解决你的问题,请参考以下文章

带有复选框的 C# WPF 目录树视图:检查构建项目失败,PropertyChanged 为空

WPF 树视图展开操作

如何在 WPF 中创建可编辑的树列表视图?

WPF XBAP 树视图无法选择子项

wpf树视图绑定[关闭]

选项卡时更改整行的背景颜色?