Search code examples
c#.netwinui-3winuiwinui-xaml

WinUI3 TreeView Hover Colour change issue


I'm working on a WinUI3 project and encountering an issue with a TreeView. In my code, I've set up a TreeView in XAML and am binding data from the code-behind. To manage the foreground color of the TreeView, I'm using a custom class called TreeNode. However, when I change the foreground color programmatically, I encounter a problem where the color does not update correctly on hover.

I've attached a GIF of the UI and the relevant code for reference.

Gif Image Link: https://ibb.co/jrBQRNp

Xaml Code:

<?xml version="1.0" encoding="utf-8"?>
<Window x:Class="TreeView.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TreeView"
        xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">

    <StackPanel Orientation="Horizontal"
                HorizontalAlignment="Center"
                VerticalAlignment="Center">
        <Grid Margin="3"
              BorderThickness="1"
              Width="239"
              Height="220"
              BorderBrush="Black"
              HorizontalAlignment="Center">
            <TreeView FontWeight="Bold"
                      ItemsSource="{x:Bind TreeNodes, Mode=OneWay}">
                <TreeView.ItemTemplate>
                    <DataTemplate x:DataType="local:TreeNode">
                        <TreeViewItem Foreground="{Binding Foreground}"
                                      Content="{Binding Name}"
                                      ItemsSource="{Binding Children}" />
                    </DataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
        </Grid>
    </StackPanel>
</Window>

Code Behind File:

  public sealed partial class MainWindow : Window
  {
      public ObservableCollection<TreeNode> TreeNodes { get; set; }

      public MainWindow()
      {
          this.InitializeComponent();

          TreeNodes = new ObservableCollection<TreeNode>();

          // Example data
          var superParent = new TreeNode { Name = "Super Parent", Foreground = new SolidColorBrush(Colors.DarkSeaGreen) };

          var parent1 = new TreeNode { Name = "Parent1", Foreground = new SolidColorBrush(Colors.Blue) };
          parent1.Children.Add(new TreeNode { Name = "Child1 of Parent1", Foreground = new SolidColorBrush(Colors.Red) });
          parent1.Children.Add(new TreeNode { Name = "Child2 of Parent1" , Foreground = new SolidColorBrush(Colors.Red) });
          parent1.Children.Add(new TreeNode { Name = "Child3 of Parent1", Foreground = new SolidColorBrush(Colors.Red) });

          superParent.Children.Add(parent1);


          var parent2 = new TreeNode { Name = "Parent2" };
          parent2.Children.Add(new TreeNode { Name = "Child1 of Parent2" , Foreground = new SolidColorBrush(Colors.Red) });
          parent2.Children.Add(new TreeNode { Name = "Child2 of Parent2", Foreground = new SolidColorBrush(Colors.Red) });
          parent2.Children.Add(new TreeNode { Name = "Child3 of Parent2" , Foreground = new SolidColorBrush(Colors.Red) });

          superParent.Children.Add(parent2);

          var parent3 = new TreeNode { Name = "Parent3" };
          parent3.Children.Add(new TreeNode { Name = "Child1 of Parent3", Foreground = new SolidColorBrush(Colors.Red) });
          parent3.Children.Add(new TreeNode { Name = "Child2 of Parent3" , Foreground = new SolidColorBrush(Colors.Red) });
          parent3.Children.Add(new TreeNode { Name = "Child3 of Parent3" , Foreground = new SolidColorBrush(Colors.Red) });

          superParent.Children.Add(parent3);

          TreeNodes.Add(superParent);
      }
  }

TreeNode Custom Class:

   public class TreeNode
   {
       public string Name { get; set; }
       public SolidColorBrush Foreground { get; set; }
       public ObservableCollection<TreeNode> Children { get; set; } = new ObservableCollection<TreeNode>();

   }

I've attempted to define some styles to address this issue, but unfortunately, they haven't worked for me

Updated: I added this style to my XAML code, and that resolved the issue.

   <TreeView.Resources>
       <SolidColorBrush x:Key="TreeViewItemForegroundPointerOver"
                        Color="White" />
       <SolidColorBrush x:Key="TreeViewItemBackgroundSelected"
                        Color="Gray" />
       <SolidColorBrush x:Key="TreeViewItemBackgroundSelectedPointerOver"
                        Color="Gray" />
       <SolidColorBrush x:Key="TreeViewItemBackgroundSelectedPressed"
                        Color="Gray" />
       <SolidColorBrush x:Key="TreeViewItemBackgroundSelectedDisabled"
                        Color="Gray" />
       <SolidColorBrush x:Key="TreeViewItemForegroundSelected"
                        Color="White" />
       <SolidColorBrush x:Key="TreeViewItemForegroundSelectedPointerOver"
                        Color="White" />
       <SolidColorBrush x:Key="TreeViewItemForegroundSelectedPressed"
                        Color="White" />
       <SolidColorBrush x:Key="TreeViewItemForegroundSelectedDisabled"
                        Color="White" />
       <SolidColorBrush x:Key="TreeViewItemBackgroundPointerOver"
                        Color="Gray" />
   </TreeView.Resources>

Solution

  • You can override TreeViewItemForegroundPointerOver. For example:

    <TreeView ...>
        <TreeView.Resources>
            <SolidColorBrush x:Key="TreeViewItemForegroundPointerOver" Color="Red" />
        </TreeView.Resources>
    </TreeView>
    

    Or in code-behind:

    // You need to set a name to the TreeView.
    MyTreeView.Resources["TreeViewItemForegroundPointerOver"] = new SolidColorBrush(Colors.Red);
    

    You can learn about TreeViewItemForegroundPointerOver in the generic.xaml file.