← About Jeff

Using a value converter to bind to Visibility in the Silverlight data grid

July 13, 2008

I received a question a few weeks ago from a customer who was trying to show and hide a button inside a data grid row.  This developer had a boolean property exposed inside the data model that indicated whether an item was in stock; at that time, a "Buy" button should appear.

By using a type converter and data binding, we can make this scenario work pretty easily.  Here's the finished appearance that we're going for:

The solution I recommended had these components:

  • Create a value converter for bool and System.Windows.Visibility.  (IValueConverter)
  • Add the converter into the user control's resources.
  • Use a DataGridTemplateColumn to define the optional button, and data bind the Visibility property of the button to the boolean data source property, specifying the converter.

Defining the data

I'm sticking to a really simple data definition for binding.

using System;

/// <summary>
/// My awesome data model.
/// </summary>
public class MyData
{
    /// <summary>
    /// The item name.
    /// </summary>
    public string Name
    { 
        get;
        set;
    }

    /// <summary>
    /// Whether the item can be purchased right now.
    /// </summary>
    public bool IsBuyable
    {
        get;
        set;
    }
}

Creating the value converter

Next, we need to create a converter to go between bool values and Visibility.  Here's that:

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

/// <summary>
/// A type converter for visibility and boolean values.
/// </summary>
public class VisibilityConverter : IValueConverter
{
    public object Convert(
        object value,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
        bool visibility = (bool)value;
        return visibility ? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(
        object value,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
        Visibility visibility = (Visibility)value;
        return (visibility == Visibility.Visible);
    }
}

Naming the converter in the UserControl's resources

Next, add the converter in the UserControl's resources.  In my simple project, I had to create this section - but hopefully you're already using this in your real apps! 

You may also need to add an xmlns attribute in page.xaml for your project's namespace.

    <UserControl.Resources>
        <myproject:VisibilityConverter x:Key="VisibilityConverter" />
    </UserControl.Resources>

The "x:Key" attribute defines the name that you'll use inside your binding statements to make use of the converter.

Using DataGridTemplateColumn

The DataGridTemplateColumn lets you create advanced cells. 

If you're looking for juicy details about the DataGrid in detail, head on over to the tutorials that Scott Morrison has created.

Make sure to set the AutoGenerateColumns property of the DataGrid to false, so that your template column is picked up.

Here's the DataGrid element inside my page's Grid:

<my:DataGrid x:Name="SampleGrid" AutoGenerateColumns="False">
    <my:DataGrid.Columns>
        <my:DataGridTextColumn Header="Product Name" 
                               DisplayMemberBinding="{Binding Name}" />
        <my:DataGridTemplateColumn Header="Make a purchase">
            <my:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button Content="Add to cart" 
                            Visibility="{Binding IsBuyable, Converter={StaticResource VisibilityConverter}}"
                        FontFamily="Trebuchet MS" FontSize="9" Margin="4,3,4,3"/>
                </DataTemplate>
            </my:DataGridTemplateColumn.CellTemplate>
        </my:DataGridTemplateColumn>
    </my:DataGrid.Columns>
</my:DataGrid>

And finally, here's the sample data I used:

List<MyData> sampleData = new List<MyData>
{
    new MyData
    {
        Name = "Apple iPhone 3G",
        IsBuyable = true
    },
    new MyData
    {
        Name = "Microsoft Silverlight 2",
        IsBuyable = false,
    },
    new MyData
    {
        Name = "Microsoft .NET Framework 3.5"
    },
    new MyData 
    { 
        Name = "Microsoft Visual Studio 2008", 
        IsBuyable = true 
    },
    new MyData
    {
        Name = "Microsoft Windows Vista Ultimate",
        IsBuyable = true
    }
};

SampleGrid.ItemsSource = sampleData;

And here's our finished product:

Hope this helps.