Search code examples
wpftreeview

Setting foreground color for TreeViewItem from code behind


I need to set custom color for TreeViewControl in runtime so I need to add style in code. This is my tree control:

<UserControl x:Class="Client.WPF.CommonControls.Controls.Common.Tree"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:local="clr-namespace:Client.WPF.CommonControls.Controls"
         xmlns:sf="http://schemas.syncfusion.com/wpf"
         xmlns:vm="clr-namespace:ClientCore.ViewModels;assembly=ClientCore"
         xmlns:models="clr-namespace:Client.WPF.CommonControls.Models"
         xmlns:metaInfos="clr-namespace:Base.MetaInfos;assembly=PresentationBase"
         mc:Ignorable="d" >

<UserControl.DataContext>
    <models:TreeViewModel></models:TreeViewModel>
</UserControl.DataContext>


<TreeView Name="TreeViewNodes" ItemsSource="{Binding TopNodes}" SelectedValuePath="{Binding SelectedStarElement}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate DataType="{x:Type metaInfos:Element}" ItemsSource="{Binding Children}">
            <TextBlock Text="{Binding Path=Caption}"
                       Foreground="Blue"
                       TextAlignment="Left"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Center"
                       />
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

And when i'm building window with control i fire this method to add styles;

public void AdjustAppearance(Appearance appearance)
    {
        if (appearance!= null)
        {
            if (!appearance.BackColor.isEmpty)
            {
                Background = StyleHelper.GetSolidColor(appearance.BackColor);
                TreeViewNodes.Background = StyleHelper.GetSolidColor(appearance.BackColor);
            }
            else
            {
                Background = new SolidColorBrush(Colors.White);
                TreeViewNodes.Background = new SolidColorBrush(Colors.White);
            }

            if (!appearance.ForeColor.isEmpty)
            {
                Foreground = StyleHelper.GetSolidColor(appearance.ForeColor);
                TreeViewNodes.Foreground = StyleHelper.GetSolidColor(appearance.ForeColor);
            }

            if (!appearance.BorderColor.isEmpty)
            {
                BorderBrush = StyleHelper.GetSolidColor(appearance.BorderColor);
            }

            if (appearance.BorderThickness >= 0)
            {
                BorderThickness = new Thickness(appearance.BorderThickness);
            }

            if (appearance.ForeColor != null && !appearance.ForeColor.isEmpty)
            {
                //Foreground = StyleHelper.GetSolidColor(appearance.ForeColor);
                //TreeViewNodes.Foreground = StyleHelper.GetSolidColor(appearance.ForeColor);
                //StyleHelper.SetStyleForControlItemContainerStyle(
                //    this, typeof(TextBlock), TextBlock.ForegroundProperty, appearance.ForeColor);

                Style textStyle = new Style(typeof(TextBlock));
                textStyle.Setters.Add(new Setter(ForegroundProperty, StyleHelper.GetSolidColor(appearance.ForeColor)));
                TreeViewNodes.Resources.Add("textStyle", textStyle);

                //Foreground = new SolidColorBrush(Colors.Aqua);
                //StyleHelper.SetStyleForControlItemContainerStyle(
                //    this, typeof(TreeViewItemAdv), TreeViewItemAdv.ForegroundProperty, appearance.ForeColor);

            }
            if (appearance.FontData.SizeInPoints > 0)
            {
                FontSize = StyleHelper.PointsToPixels(appearance.FontData.SizeInPoints);
                TreeViewNodes.FontSize = StyleHelper.PointsToPixels(appearance.FontData.SizeInPoints);
            }

            if (!string.IsNullOrEmpty(appearance.FontData.Name))
            {
                FontFamily = new FontFamily(appearance.FontData.Name);
                TreeViewNodes.FontFamily = new FontFamily(appearance.FontData.Name);
            }

            this.FontWeight = appearance.FontData.Bold ? FontWeights.Bold : FontWeights.Normal;
            TreeViewNodes.FontWeight = appearance.FontData.Bold ? FontWeights.Bold : FontWeights.Normal;
            this.FontStyle = appearance.FontData.Italic ? FontStyles.Italic : FontStyles.Normal;
            TreeViewNodes.FontStyle = appearance.FontData.Italic ? FontStyles.Italic : FontStyles.Normal;
        }
    }

I have tried with different methods, one like this:

    public static void SetStyleForControlItemContainerStyle(Control control, Type typeOfControl, DependencyProperty property, object value)
    {
        if (typeOfControl == null) return;
        var itemContainerStyle = (control as ItemsControl)?.ItemContainerStyle;
        if (itemContainerStyle == null) itemContainerStyle = new Style(typeOfControl);
        itemContainerStyle.Setters.Add(new Setter(property, value));
    }

Could somebody provide me with any guidance? I feel lost right now because all other properties work. I can set text to be bold for example.

Thank you for reading this.


Solution

  • It's not working because you set the color of the TextBlock statically to Blue. It won't change by setting TreeViewItem.Foreground.
    Also don't create styles or templates in C#.

    Don't explicitly set the TextBlock.Foreground. Just set the TreeViewItem.Foreground. By default Control.Foreground will be inherited by child elements. This means the TextBlock.Foreground will implicitly inherit the TreeViewItem.Foreground.

    Create a resource that serves as the binding source for the default Style of the e.g., TreeViewItem and add it to the application's ResourceDictionary in the App.xaml. It should contain all dynamic properties of your layout e.g. colors, margins, font, font size etc.

    ThemeProvider.cs

    class ThemeProvider : DependencyObject
    {
      public static readonly DependencyProperty TreeViewItemForegroundProperty = DependencyProperty.Register(
        "TreeViewItemForeground",
        typeof(Brush),
        typeof(ThemeProvider),
        new PropertyMetadata(Brushes.Blue));
    
      public Brush TreeViewItemForeground
      {
        get => (Brush) GetValue(ThemeProvider.TreeViewItemForegroundProperty);
        set => SetValue(ThemeProvider.TreeViewItemForegroundProperty, value);
      }
    }
    

    App.xaml

    <Application>
      <Application.Resources>
        <ResourceDictionar>
          <ThemeProvider x:Key="ThemeProvider" />
        </ResourceDictionar>
      </Application.Resources>
    <Application>
    

    Tree.xaml

    <TreeView Name="TreeViewNodes">
      <TreeView.ItemTemplate>
        <HierarchicalDataTemplate DataType="{x:Type metaInfos:Element}" ItemsSource="{Binding Children}">
          <TextBlock Text="{Binding Path=Caption}"
                     TextAlignment="Left"
                     HorizontalAlignment="Left"
                     VerticalAlignment="Center" />
        </HierarchicalDataTemplate>
      </TreeView.ItemTemplate>
    
      <TreeView.ItemContainerStyle>
        <Style TargetType="TreeViewItem">
          <Setter Property="Foreground" 
                  Value="Binding Source={StaticResource ThemeProvider}, Path=TreeViewItemForeground}" />
        </Style>
      </TreeView.ItemContainerStyle>
    </TreeView>
    

    MainWindow.xaml.cs

    private void AdjustAppearance(Appearance appearance)
    {
      var themeProvider = Application.Current.Resources["ThemeProvider"] as ThemeProvider;
      themeProvider.TreeViewItemForeground = appearance.ForeColor;
    }