WPF TreeView: jak stylować wybrane elementy z zaokrąglonymi rogami, jak w Eksploratorze
Zaznaczony element w widoku drzewa WPF ma ciemnoniebieskie tło z "ostrymi" rogami. To wygląda na trochę przestarzałe dzisiaj:
Chciałbym zmienić tło tak, aby wyglądało jak w Eksploratorze Windows 7 (z/bez Fokusa):
To, co próbowałem do tej pory, nie usuwa oryginalnego ciemnoniebieskiego tła, ale maluje zaokrągloną obwódkę na wierzchu, aby zobaczyć ciemnoniebieski kolor na krawędziach i po lewej stronie - brzydka.
Co ciekawe, gdy moja wersja nie ma Focusa, wygląda całkiem OK:
Chciałbym powstrzymać się od redefiniowania szablonu kontrolnego jako pokazanego tutaj lub tutaj. Chcę ustawić minimalne wymagane właściwości, aby wybrany element wyglądał jak w Eksploratorze.
Alternatywa: byłbym również szczęśliwy, gdyby wybrany przedmiot wyglądał tak, jak mój teraz, gdy nie ma ostrości. Kiedy tracąc ostrość, kolor powinien zmienić się z niebieskiego na szary.
Oto Mój kod:
<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>
Rozwiązanie
Z doskonałymi odpowiedziami Sheridana i Meleaka mój TreeView wygląda teraz tak w kodzie (wynik, z którego jestem bardzo zadowolony i który jest prawie w stylu Explorera):
<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>
3 answers
Dodawanie do odpowiedzi @Sheridan
To nie jest 100% dokładne, ale powinno być dość blisko (używa kolorów z GridView
, który jest dość blisko Eksploratora 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>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-19 00:58:40
Dodaj to do TreeView.ContainerStyle
, aby usunąć domyślne tło 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>
Możesz zastąpić Black
dowolnym kolorem tekstu elementu i zaznaczonego tekstu elementu.
Style
z szarym backgorundem i użyć EventTrigger
s na zdarzeniach TreeViewItem.GotFocus
i LostFocus
, aby przełączać się między zdarzeniami Style
S.
Edytuj > > >
Jeśli chcesz być Flashem, możesz użyć animacji do zmiany między kolory tła poprzez dodanie wyzwalaczy do twojego ItemBorder Border
bezpośrednio w twoim HierarchicalDataTemplate
tak:
<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>
Zauważ, że to zadziała tylko wtedy, gdy ColorAnimation
ma From
kolor. W obecnym stanie kodu, runtime będzie szukał SolidColorBrush
ustawionego na właściwości Border.Background
, więc musisz ją ustawić. Możesz ustawić właściwość ColorAnimation.From
bezpośrednio zamiast niej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-29 09:49:17
Windows 10 TreeView (i ListView) Style
Na początku szukałem sposobu, aby zastosować schemat kolorów systemu Windows 10 do TreeViewItem, w tym- IsMouseOver tylko na bieżącym elemencie
- Windows 10 kolory, które WPF już stosuje je do ListBox (NIE Windows Explorer)
Jeśli ktoś z Was szuka dokładnie tego, prosimy o skorzystanie z poniższego kodu. Użyłem rozwiązania Helge Klein w kwestii IsMouseOver i zastosowano Kolory systemu Windows 10 do XAML. Dlatego proponuję to jako uzupełnienie przyjętej odpowiedzi.
Zobacz również poniżej, aby znaleźć słowo na ListView
i ComboBox
, jak również.
Zrzut ekranu
App.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 (źródło opublikowane przez Helge Klein, drobne zmiany / uproszczenie )
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 i ComboBox: W Windows 7 (i 8?) , spowoduje to, że projekt z TreeView do ListBox/ListView i ComboBox będzie się różnić. Dlatego, jeśli chcesz zastosować ten schemat kolorów również do tych typów sterowania, użyj tego:
<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>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-14 09:17:30