Changing the Foreground Colour of an XAML Control Using a Binding Convertor

This article shows how to easily change the foreground object of an XAML control, such as a TextBlock, using a binding convertor.

This article uses the code base that I used in the "Display a Message When the ListView Becomes Empty in Windows Store Apps" article that I previously published. See the previous article for a more detailed explanation of anything you are unsure of.
 
The great thing about XAML is that you can easily change the foreground colour of controls, such as a TextBlock, to be exactly what you want it to be. Whether that is through the built-in colour names or a HEX colour is completely your choice.
 
However there may be times when you simply wish to change the colour of a control dependent on the value that it is displaying. In this example we will be using a TextBlock that has it's Text value assigned to it using data context binding.
 
MainPage.xaml
  1. <Page        
  2.     x:Class="CSharpCornerTestProject.MainPage"    
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
  5.     xmlns:local="using:CSharpCornerTestProject"    
  6.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    
  7.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"        
  8.     mc:Ignorable="d">    
  9.     <Page.Resources>    
  10.         <DataTemplate x:Key="listViewItems">    
  11.             <StackPanel>    
  12.                 <TextBlock        
  13.                     Margin="5,5,5,5"        
  14.                     Text="{Binding Name}"        
  15.                     Style="{StaticResource BaseTextBlockStyle}"/>    
  16.                 <TextBlock        
  17.                     Margin="5,5,5,5"        
  18.                     Text="{Binding Ripeness}"        
  19.                     Style="{StaticResource BaseTextBlockStyle}"/>    
  20.             </StackPanel>    
  21.         </DataTemplate>    
  22.     </Page.Resources>    
  23.     <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">    
  24.         <ListView        
  25.             x:Name="listViewTest"        
  26.             Margin="5,5,5,5"        
  27.             VerticalAlignment="Center"        
  28.             HorizontalAlignment="Center"        
  29.             ItemsSource="{Binding}"        
  30.             SelectionMode="None"        
  31.             IsItemClickEnabled="False"        
  32.             ItemTemplate="{StaticResource listViewItems}"        
  33.             ContainerContentChanging="listViewUpdated"></ListView>    
  34.         <TextBlock        
  35.             x:Name="listViewNoItems"        
  36.             Margin="5,5,5,5"        
  37.             VerticalAlignment="Center"        
  38.             HorizontalAlignment="Center"        
  39.             Text="There are no fruits in your list to display!"        
  40.             Style="{StaticResource BaseTextBlockStyle}"        
  41.             Visibility="Collapsed"/>    
  42.         <Button        
  43.             Width="150"        
  44.             Height="50"        
  45.             Margin="20"        
  46.             VerticalAlignment="Center"        
  47.             HorizontalAlignment="Right"        
  48.             Content="Clear fruit"        
  49.             Click="clearFruitBasket"/>    
  50.     </Grid>    
  51. </Page>  
MainPage.xaml.cs
  1. using System.Collections.ObjectModel;    
  2. using Windows.UI.Xaml;    
  3. using Windows.UI.Xaml.Controls;    
  4. namespace CSharpCornerTestProject     
  5. {    
  6.     public class Fruit     
  7.     {    
  8.         public string Name    
  9.         {    
  10.             get;    
  11.             set;    
  12.         }    
  13.         public string Ripeness     
  14.         {    
  15.             get;    
  16.             set;    
  17.         }    
  18.     }    
  19.     public sealed partial class MainPage: Page     
  20.     {    
  21.         private ObservableCollection < Fruit > fruitList = new ObservableCollection < Fruit > ();    
  22.         public MainPage()     
  23.         {    
  24.             this.InitializeComponent();    
  25.             fruitList.Add(new Fruit()    
  26.             {    
  27.                 Name = "Apple", Ripeness = "Ok"    
  28.             });    
  29.             fruitList.Add(new Fruit()    
  30.             {    
  31.                 Name = "Banana", Ripeness = "Bad"    
  32.             });    
  33.             fruitList.Add(new Fruit()    
  34.             {    
  35.                 Name = "Kiwi", Ripeness = "Rotten"    
  36.             });    
  37.     
  38.             listViewTest.ItemsSource = fruitList;    
  39.         }    
  40.         private void listViewUpdated(ListViewBase sender, ContainerContentChangingEventArgs args) {    
  41.             if (listViewTest.Items.Count == 0)     
  42.             {    
  43.                 listViewNoItems.Visibility = Visibility.Visible;    
  44.                 listViewTest.Visibility = Visibility.Collapsed;    
  45.             }     
  46.             else     
  47.             {    
  48.                 listViewNoItems.Visibility = Visibility.Collapsed;    
  49.                 listViewTest.Visibility = Visibility.Visible;    
  50.             }    
  51.         }    
  52.         private void clearFruitBasket(object sender, RoutedEventArgs e)    
  53.         {    
  54.             // clear the fruit list!        
  55.             if (fruitList != null) fruitList.Clear();    
  56.         }    
  57.     }    
  58. }   
As I stated above, this is the code base that we used in my previous article about displaying a message once a ListView control no longer has any items in it. We will slightly modify this now so that the ripeness of the fruit in our fruit basket is colour-coded depending on its value.
 
The first thing we need to do is to create a convertor class for us to use when binding data to the list view. This is a very simple affair and just requires you to add a new "Class file" to your project.
 
FruitBasketConvertor.cs
  1. using System;    
  2. using Windows.UI;    
  3. using Windows.UI.Xaml.Data;    
  4. using Windows.UI.Xaml.Media;    
  5. namespace CSharpCornerTestProject.Convertors     
  6. {    
  7.     public class fruitBasketRipenessForegroundConvertor: IValueConverter    
  8.     {    
  9.         public object Convert(object value, Type targetType, object parameter, string language)    
  10.         {    
  11.             string ripeness = (value as string);    
  12.             if (ripeness == "Ok"return new SolidColorBrush(Colors.ForestGreen);    
  13.             else if (ripeness == "Bad"return new SolidColorBrush(Colors.OrangeRed);    
  14.             else if (ripeness == "Rotten"return new SolidColorBrush(Colors.DarkRed);    
  15.             // default return value of lime green      
  16.             return new SolidColorBrush(Colors.LimeGreen);    
  17.         }    
  18.         public object ConvertBack(object value, Type targetType, object parameter, string language)    
  19.         {    
  20.             throw new NotImplementedException();    
  21.         }    
  22.     }    
  23. }    
That is all there is to our file, just those 30 lines. Do take note, however, that we have placed the convertors under their own namespace, CSharpCornerTestProject.Convertors.
 
Using convertors isn't all as daunting as it seems. You create your own custom class, making sure that it derives from IValueConvertor.  Then all we need are two functions.
  1. public object Convert(object value, Type targetType, object parameter, string language)  
  2. {  
  3.     // your convertor code goes here    
  4. }  
  5. public object ConvertBack(object value, Type targetType, object parameter, string language)   
  6. {  
  7.     // your convert back code goes here    
  8. }  
The Convert function takes the raw value of your binding and allows you to access anything associated with that, whether it is a class, a string, or anything of your choosing.
 
The ConvertBack function is generally not used all that often and so in our example we are leaving it as throw new NotImplementedException();. Its main use would be if you wanted to convert the value back to its original state.
 
Returning to the Convert function, this is very simple and there isn't all that much to it at all. All we do here is take the object value and store it into our string variable, ripeness.  
  1. public object Convert(object value, Type targetType, object parameter, string language)   
  2. {  
  3.     string ripeness = (value as string);  
  4.     if (ripeness == "Ok"return new SolidColorBrush(Colors.ForestGreen);  
  5.     else if (ripeness == "Bad"return new SolidColorBrush(Colors.OrangeRed);  
  6.     else if (ripeness == "Rotten"return new SolidColorBrush(Colors.DarkRed);  
  7.     // default return value of lime green      
  8.     return new SolidColorBrush(Colors.LimeGreen);  
  9. }  
Since we have different forms of Ripeness in our Fruit class, we have three separate if statements to determine which colour we should return for our Foreground colour.
 
When converting a Foreground (or Background) XAML member, it expects a SolidColorBrush to be returned and so that is what we are giving it.
 
That is everything that we need to do for the code side of things with our convertor, the next step is much simpler and only requires us to add three new lines of code to the existing MainPage.xaml file that we have.
 
In our Page control, we need to add a new member, highlighted in bold Green.
  1. <Page  
  2. x:Class="CSharpCornerTestProject.MainPage"  
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  5.     xmlns:local="using:CSharpCornerTestProject"  
  6.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
  7.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
  8.     xmlns:utils="using:CSharpCornerTestProject.Convertors"  
  9. mc:Ignorable="d">  
This will allow us to access the custom convertor class that we just created in FruitBasketConvertor.cs.
 
Now that we have done that, we need to add our convertor function as a page resource and provide it a key. This will allow us to access it when using the binding convertor. Once again, the addition is highlighted in bold Green.
  1. <Page.Resources>  
  2.     <utils:fruitBasketRipenessForegroundConvertor x:Key="ripenessConvertor"/>  
  3.     <DataTemplate x:Key="listViewItems">  
  4.         <StackPanel>  
  5.             <TextBlock      
  6.                 Margin="5,5,5,5"      
  7.                 Text="{Binding Name}"      
  8.                 Style="{StaticResource BaseTextBlockStyle}"/>  
  9.             <TextBlock      
  10.                 Margin="5,5,5,5"      
  11.                 Text="{Binding Ripeness}"      
  12.                 Style="{StaticResource BaseTextBlockStyle}"/>  
  13.         </StackPanel>  
  14.     </DataTemplate>  
  15. </Page.Resources>
Now that we have given our convertor a key, we can access it anywhere in the MainPage.xaml file when we are binding items. We just have one last thing to do now, that is to add a Foreground member to the TextBlock control that is telling us how ripe our fruit is.
  1. <TextBlock    
  2.     Foreground="{Binding Ripeness, Converter={StaticResource ripenessConvertor}}"    
  3.     Margin="5,5,5,5"    
  4.     Text="{Binding Ripeness}"    
  5.     Style="{StaticResource BaseTextBlockStyle}"/>    
That is everything that we need to do to start dynamically changing the foreground colour of our XAML controls dependent on what the value they're displaying is. If you run the app your fruit basket should now show the Ripeness of each fruit in the three different colours that we assigned earlier on whilst creating our convertor function.
 
 
Thanks for reading! If you want to keep up-to-date with what I'm working on then be sure you follow me on Twitter: @Forceh91.