WPF TreeView:如何像在资源管理器中一样使用圆角设置所选项目的样式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5047576/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF TreeView: How to style selected items with rounded corners like in Explorer
提问by Helge Klein
The selected item in a WPF TreeView has a dark blue background with "sharp" corners. That looks a bit dated today:
WPF TreeView 中的选定项具有带有“锐利”角的深蓝色背景。今天看起来有点过时了:
I would like to change the background to look like in Explorer of Windows 7 (with/without focus):
我想将背景更改为 Windows 7 资源管理器中的样子(有/无焦点):
What I tried so far does not remove the original dark blue background but paints a rounded border on top of it so that you see the dark blue color at the edges and at the left side - ugly.
到目前为止,我尝试的方法并没有删除原始的深蓝色背景,而是在其顶部绘制了一个圆形边框,以便您在边缘和左侧看到深蓝色 - 丑陋。
Interestingly, when my version does not have the focus, it looks pretty OK:
有趣的是,当我的版本没有焦点时,它看起来还不错:
I would like to refrain from redefining the control template as shownhere or here. I want to set the minimum required properties to make the selected item look like in Explorer.
我想避免重新定义此处或此处所示的控件模板。我想设置所需的最低属性,以使所选项目在资源管理器中看起来像。
Alternative:I would also be happy to have the focused selected item look like mine does now when it does not have the focus. When losing the focus, the color should change from blue to grey.
替代方案:我也很高兴让聚焦的选定项目在没有焦点时看起来像我现在的样子。失去焦点时,颜色应从蓝色变为灰色。
Here is my code:
这是我的代码:
<TreeView
x:Name="TreeView"
ItemsSource="{Binding TopLevelNodes}"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="#FF7DA2CE" />
<Setter Property="Background" Value="#FFCCE2FC" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type viewmodels:ObjectBaseViewModel}" ItemsSource="{Binding Children}">
<Border Name="ItemBorder" CornerRadius="2" Background="{Binding Background, RelativeSource={RelativeSource AncestorType=TreeViewItem}}"
BorderBrush="{Binding BorderBrush, RelativeSource={RelativeSource AncestorType=TreeViewItem}}" BorderThickness="1">
<StackPanel Orientation="Horizontal" Margin="2">
<Image Name="icon" Source="/ExplorerTreeView/Images/folder.png"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</Border>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
Solution
解决方案
With the excellent answers of Sheridan and Meleak my TreeView now looks like this in code (a result I am very happy with and which is pretty near Explorer's style):
有了 Sheridan 和 Meleak 的出色回答,我的 TreeView 现在在代码中看起来像这样(我很满意这个结果,并且非常接近 Explorer 的风格):
<TreeView
...
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<!-- Style for the selected item -->
<Setter Property="BorderThickness" Value="1"/>
<Style.Triggers>
<!-- Selected and has focus -->
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="#7DA2CE"/>
</Trigger>
<!-- Mouse over -->
<Trigger Property="helpers:TreeView_IsMouseDirectlyOverItem.IsMouseDirectlyOverItem" Value="True">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFFAFBFD" Offset="0"/>
<GradientStop Color="#FFEBF3FD" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="BorderBrush" Value="#B8D6FB"/>
</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="#D9D9D9"/>
</MultiTrigger>
</Style.Triggers>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="2"/>
</Style>
</Style.Resources>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type viewmodels:ObjectBaseViewModel}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal" Margin="2,1,5,2">
<Grid Margin="0,0,3,0">
<Image Name="icon" Source="/ExplorerTreeView/Images/folder.png"/>
</Grid>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
<!-- Brushes for the selected item -->
<LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFDCEBFC" Offset="0"/>
<GradientStop Color="#FFC1DBFC" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="{x:Static SystemColors.ControlBrushKey}" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFF8F8F8" Offset="0"/>
<GradientStop Color="#FFE5E5E5" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
</TreeView.Resources>
</TreeView>
采纳答案by Fredrik Hedblad
Adding to @Sheridan's answer
This isn't a 100% accurate but should get you pretty close (it's using the colors from GridView
which is pretty close to Windows Explorer)
添加到@Sheridan 的答案
这不是 100% 准确,但应该让您非常接近(它使用的颜色与GridView
Windows 资源管理器非常接近)
<TreeView ...>
<TreeView.Resources>
<LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFD9F4FF" Offset="0"/>
<GradientStop Color="#FF9BDDFB" Offset="1"/>
</LinearGradientBrush>
<LinearGradientBrush x:Key="{x:Static SystemColors.ControlBrushKey}" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFEEEDED" Offset="0"/>
<GradientStop Color="#FFDDDDDD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="BorderThickness" Value="1.5"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="#adc6e5"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"/>
<Condition Property="IsSelectionActive" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="LightGray"/>
</MultiTrigger>
</Style.Triggers>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="2"/>
</Style>
</Style.Resources>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
回答by Sheridan
Add this into your TreeView.ContainerStyle
to remove the default blue
background.
将此添加到您TreeView.ContainerStyle
的删除默认blue
背景中。
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
</Style.Resources>
You can replace the Black
with whatever colour you want your item text and selected item text to be.
您可以将 替换为Black
您希望项目文本和所选项目文本的任何颜色。
To have a grey background when not focused, you could set up a 'non focused' Style
with a grey backgorund and use EventTrigger
s on the TreeViewItem.GotFocus
and LostFocus
events to switch between the Style
s.
要在未聚焦时具有灰色背景,您可以设置一个带有灰色背景的“非聚焦” Style
,并EventTrigger
在TreeViewItem.GotFocus
和LostFocus
事件上使用s 在Style
s之间切换。
EDIT>>>
编辑>>>
If you want to be flash, you can use animations to change between the background colours by adding triggers to your ItemBorder Border
directly in your HierarchicalDataTemplate
like so:
如果你想成为 Flash,你可以使用动画来改变背景颜色,方法是ItemBorder Border
直接向你添加触发器,HierarchicalDataTemplate
如下所示:
<Border.Triggers>
<EventTrigger RoutedEvent="Border.GotFocus">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="YourColour" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Border.LostFocus">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="LightGray" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Border.Triggers>
Note that this will only work if the ColorAnimation
has a From
colour. As this code stands, the runtime will look for a SolidColorBrush
set on the Border.Background
property, so you must set one. You could set the ColorAnimation.From
property directly instead.
请注意,这仅在ColorAnimation
具有From
颜色时才有效。就这段代码而言,运行时将SolidColorBrush
在Border.Background
属性上寻找一个集合,因此您必须设置一个。您可以ColorAnimation.From
直接设置属性。
回答by bytecode77
Windows 10 TreeView (and ListView)Style
Windows 10 TreeView (和 ListView)样式
I was originally looking for a way to apply the Windows 10 color scheme to a TreeViewItem, including
我最初是在寻找一种将 Windows 10 配色方案应用于 TreeViewItem 的方法,包括
- IsMouseOver on current item only
- Windows 10 colors which WPF already applies them to ListBox (not Windows Explorer)
- IsMouseOver 仅在当前项目上
- WPF 已将它们应用于 ListBox (而不是 Windows 资源管理器)的Windows 10 颜色
If any of you are looking for exactly this, please feel free to take the code below. I used Helge Klein's solution for the IsMouseOver issue and applied the Windows 10 colors to the XAML. Therefore I propose this as an addition to the accepted answer.
如果你们中的任何人正在寻找这个,请随时使用下面的代码。我使用 Helge Klein 的 IsMouseOver 问题解决方案并将 Windows 10 颜色应用于 XAML。因此,我建议将此作为已接受答案的补充。
Also, see below for a word on ListView
and ComboBox
as well.
另外,请参阅下文了解有关ListView
和 的信息ComboBox
。
Screenshot
截屏
App.xaml
应用程序.xaml
<Style TargetType="{x:Type TreeView}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#CBE8F6" />
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="#F6F6F6" />
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
</Style.Resources>
</Style>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="BorderThickness" Value="1" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="#26A0DA" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="local:TreeViewItemHelper.IsMouseDirectlyOverItem" Value="True" />
<Condition Property="IsSelected" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="#E5F3FB" />
<Setter Property="BorderBrush" Value="#70C0E7" />
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True" />
<Condition Property="IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="#DADADA" />
</MultiTrigger>
</Style.Triggers>
</Style>
TreeViewItemHelper(Sourceas posted by Helge Klein, minor changes / simplification)
TreeViewItemHelper(来源由 Helge Klein 发布,小改动/简化)
public static class TreeViewItemHelper
{
private static TreeViewItem CurrentItem;
private static readonly RoutedEvent UpdateOverItemEvent = EventManager.RegisterRoutedEvent("UpdateOverItem", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItemHelper));
private static readonly DependencyPropertyKey IsMouseDirectlyOverItemKey = DependencyProperty.RegisterAttachedReadOnly("IsMouseDirectlyOverItem", typeof(bool), typeof(TreeViewItemHelper), new FrameworkPropertyMetadata(null, new CoerceValueCallback(CalculateIsMouseDirectlyOverItem)));
public static readonly DependencyProperty IsMouseDirectlyOverItemProperty = IsMouseDirectlyOverItemKey.DependencyProperty;
static TreeViewItemHelper()
{
EventManager.RegisterClassHandler(typeof(TreeViewItem), UIElement.MouseEnterEvent, new MouseEventHandler(OnMouseTransition), true);
EventManager.RegisterClassHandler(typeof(TreeViewItem), UIElement.MouseLeaveEvent, new MouseEventHandler(OnMouseTransition), true);
EventManager.RegisterClassHandler(typeof(TreeViewItem), UpdateOverItemEvent, new RoutedEventHandler(OnUpdateOverItem));
}
public static bool GetIsMouseDirectlyOverItem(DependencyObject obj)
{
return (bool)obj.GetValue(IsMouseDirectlyOverItemProperty);
}
private static object CalculateIsMouseDirectlyOverItem(DependencyObject item, object value)
{
return item == CurrentItem;
}
private static void OnUpdateOverItem(object sender, RoutedEventArgs e)
{
CurrentItem = sender as TreeViewItem;
CurrentItem.InvalidateProperty(IsMouseDirectlyOverItemProperty);
e.Handled = true;
}
private static void OnMouseTransition(object sender, MouseEventArgs e)
{
lock (IsMouseDirectlyOverItemProperty)
{
if (CurrentItem != null)
{
DependencyObject oldItem = CurrentItem;
CurrentItem = null;
oldItem.InvalidateProperty(IsMouseDirectlyOverItemProperty);
}
Mouse.DirectlyOver?.RaiseEvent(new RoutedEventArgs(UpdateOverItemEvent));
}
}
}
ListBox/ListView and ComboBox:In Windows 7 (and 8?), this will cause the design from TreeView to ListBox/ListView and ComboBox to differ. Therefore, if you want to apply this color scheme to these control types as well, too, use this:
ListBox/ListView 和 ComboBox:在 Windows 7 (和 8?)中,这将导致从 TreeView 到 ListBox/ListView 和 ComboBox 的设计不同。因此,如果您也想将此配色方案应用于这些控件类型,请使用以下命令:
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Name="Border" BorderThickness="1" Background="Transparent">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="#E5F3FB" />
<Setter TargetName="Border" Property="BorderBrush" Value="#70C0E7" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#CBE8F6" />
<Setter TargetName="Border" Property="BorderBrush" Value="#26A0DA" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter TargetName="Border" Property="Background" Value="#F6F6F6" />
<Setter TargetName="Border" Property="BorderBrush" Value="#DADADA" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}" />
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border Name="Border" BorderThickness="1" Padding="1" Background="Transparent">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="#E5F3FB" />
<Setter TargetName="Border" Property="BorderBrush" Value="#70C0E7" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#CBE8F6" />
<Setter TargetName="Border" Property="BorderBrush" Value="#26A0DA" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>