Using XAML IValueConverter to Do Creative Things in C#

Value Converters are present in all flavours of XAML, from WPF to UWP; but what are they? Value Converters are used in conjunction with bindings to convert a value from one type to another, or simply change the value. Value converters are added in XAML, but created in C#. Here's an example of how one might look.

Note: I'm using WPF in this demonstration, but you'll find this article also applies in WinRT XAML and Silverlight.

Say you have a property that looks like this on an object that is set to your data context…

public bool IsReady { get; set; }

And you have a TextBlock in your XAML that could look like the following…

<TextBlock Visibility="{Binding IsReady}"
           Text="Well hello there!"/>

Given that the visibility property is not of type bool, instead, it is of type Visibility;, which is derived from the class UIElement. This binding will cause you problems. Step in the Value Converter to save the day. In my project, I've created a class named BooleanToVisibilityConverter, which implements the interface IValueConverter; and looks like the following:

public class BooleanToVisibilityConverter :
   IValueConverter
{
   public object Convert(
      object value, Type targetType, object parameter,
         CultureInfo culture)
   {
      if (!(value is bool))
         return Visibility.Collapsed;

      return (bool)value ? Visibility.Visible :
         Visibility.Collapsed;
   }

   public object ConvertBack(
      object value, Type targetType, object parameter,
         CultureInfo culture)
   {
      throw new NotImplementedException();
   }
}

Let's examine this converter. Notice that I've not implemented the ConvertBack method. This is because the binding from our property IsReady to the property on the TextBlock is one way. It's going from IsReady to TextBlock.Visibility; therefore, we only need to implement the Convert method.

The first thing I'm doing in this convert method is to check to make sure the value being passed is of type bool. If it isn't, I'm going to return Visibility.Collapsed as a default; this will make the text block disappear on the UI. Then, I'm simply checking the state of the Boolean and returning Visibility.Collapsed or Visibility.Visible accordingly.

Boolean to visibility is actually a very common use for a converter, and frameworks such as WPF come with a converter to do this out of the box. But, how do we get this converter to our text block? At the moment, this converter hasn't been applied to our binding we saw earlier, and the first thing we need to do is declare our converter in the XAML as a resource. In my WPF application, I'm going to do this in the resources of the main window like this…

<Window.Resources>
   <local:BooleanToVisibilityConverter
          x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>

Then, for the binding on the text block's visibility property, I'm going to do this…

<TextBlock
   Visibility="{Binding IsReady, Converter={StaticResource
      BooleanToVisibilityConverter}}"
   Text="Well hello there!"/>

When we run this application, you'll find that the text block is not visible at runtime, but if we add this line to the constructor of our MainWindow.xaml.cs…

public bool IsReady { get; set; }
public MainWindow()
{
   IsReady = true;
   InitializeComponent();
}

…we can change that. Be sure to set the IsReady property true before the call to InitializeComponent, because without any property change notification you will not see any change.

And that's the basics covered. If you are new to XAML or WPF, you can find an example of what's been covered so far on GitHub.

Let's Aim to Do More

Let's move on from a basic implementation of a converter; what else can we do that can really help in a project? Consider the following situation…

You have a TextBox on your UI, through which the user enters some text. However, when the user enters certain words, or perhaps even a number, you want the TextBox to do something visually. That something could be changing the colour of the text to red, but appear black normally.

Now, there are a number of ways of doing this, and the first is to build a custom TextBox. That, however, is an option that will take a bit of time, and probably more than several lines of code to complete. Then, you need to apply the custom TextBox in your XAML, and the project could have several such controls. This could be a valid option for you, but another could be to create a property your Textbox.Foreground property can bind to. Another valid option, but has its downfalls—such as extra code in the object assigned to your data context that will be needed to handle the property and change it.

That's not the option I'm going with in this article. I'm going to use a Converter, and I've constructed one that looks like this…

public class TextContainsNumbersToBrushConverter :
   IValueConverter
{
   public Brush NormalBrush { get; set; }

   public Brush HighlightBrush { get; set; }

   public object Convert(
      object value, Type targetType, object parameter,
         CultureInfo culture)
   {
      if (value == null)
         return NormalBrush;

      var text = value.ToString();

      bool result = text
         .Any(c => char.IsDigit(c));

      return result ? HighlightBrush : NormalBrush;
   }

   public object ConvertBack(
      object value, Type targetType, object parameter,
         CultureInfo culture)
   {
      throw new NotImplementedException();
   }
}

I can declare this converter in the XAML like so…

<local:TextContainsNumbersToBrushConverter
       x:Key="TextToBrushConverter"
       NormalBrush="Black"
       HighlightBrush="Red"/>

Then add a TextBox to my XAML on the main window like this…

<TextBox Text="{Binding Text, Mode=TwoWay,
                UpdateSourceTrigger=PropertyChanged}"
         Foreground="{Binding Text, Converter=
                      {StaticResource TextToBrushConverter}}"
         FontSize="32"
         Width="200"
         VerticalAlignment="Center"/>

Unlike the basic implementation we looked at earlier in this article, you will need to implement INotifyPropertyChanged on the property the TextBox.Text is bound to, which is of type string, to have this example work. There is comprehensive documentation on the interface INotifyPropertyChanged available on MSDN that can assist you with this.

When we run the application, and enter some text—without digits—into the TextBox, we can see the results in Figure 1.

IVal1
Figure 1: The application running without digits in the text

Then, let's add a digit to any given position in the text, as shown in Figure 2…

IVal2
Figure 2: The application running with digits in the text

The flexibly of the value converter is something I've come to rely on many times over the years when working with XAML, and I continue to make regular use of it. I hope it can solve problems for you, too. If you have any questions on this topic, you can find me on Twitter @GLanata.



About the Author

Gavin Lanata

Gavin has been building front-ends to software applications; desktop, web, and mobile, for several years now. Gavin often attends developer events, expanding his own knowledge in the fast paced world of IT, and lending a helping hand to developers needing a little direction navigating the world of design. Gavin has dedicated his time to the study of the many factors influencing human usage and reaction to software application. Art, design and coding name a few but certainly not the least of his tools to find the truths behind why we like and use the things we do.

Related Articles

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date