Follow Me on Instagram Subscribe via RSS Feed

Silverlight ComboBoxItem IsEnabled, SL5 Style

February 6, 2012

I was recently working with another developer on a ComboBox, where he needed to be able to disable certain items in the ComboBox (aka make them non-selectable).  Having been a while since I looked at it, all I could remember was it was not as easy as it should be.  In coming up with a solution, we realized that Silverlight 5 makes this rather easy.

So why would we want to disable a ComboBoxItem in the first place?  If you can disable individual items in a ComboBox, then you can still present the user with all of the available data, without making them all an actionable option.  In our example we are going to create a product list ComboBox.  In this scenario we want the user to see all of the products that we carry, but they should only be able to select the items that we currently have in stock.

To start off our project, we will create a new Silverlight 5 Application.  Plain and simple with no bells and whistles.

The first thing we need to do is to create our data object.  For this demo we will only have two properties, Name and IsAvailable.  Our class will also have a static method that will return our test data.

public class Product
{
    public string Name { get; set; }
    public bool IsAvailable { get; set; }

    public static IEnumerable<Product> GetProducts()
    {
        return new List<Product>()
                    {
                        new Product() { Name="Saw" , 
                            IsAvailable = true},
                        new Product() { Name="Hammer" , 
                            IsAvailable = true},
                        new Product() { Name="Clamp" , 
                            IsAvailable = false},
                        new Product() { Name="Level" , 
                            IsAvailable = true},
                    };
    }
}

Now we can create our testing UI.  It will be a simple Grid containing our CombBox and a few TextBlocks.

<Grid Width="Auto" Height="Auto" HorizontalAlignment="Center" 
      VerticalAlignment="Center">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
            
    <TextBlock Text="Combo Box : "/>
    <TextBlock Text="Selected Item : " Grid.Row="1"/>
            
    <ComboBox
            x:Name="cbTest" Grid.Column="1"
            DisplayMemberPath="Name" />
            
    <TextBlock Grid.Row="1" Grid.Column="1"
        Text="{Binding SelectedItem.Name, ElementName=cbTest}"/>
</Grid>

If you look at our ComboBox, we will be displaying the Product Name property.  The last TextBlock maps its Text property to the Name property of the SelectedItem of our ComboBox.  Fairly straight forward, right?

Just for completion sake, I added some Style resources to the UserControl.Resources in order to make the project a bit more readable.

<Style TargetType="TextBlock">
    <Setter Property="FontSize" Value="22"/>
    <Setter Property="Margin" Value="0,10,20,0"/>
</Style>
<Style TargetType="ComboBox">
    <Setter Property="FontSize" Value="22"/>
    <Setter Property="Height" Value="30"/>
    <Setter Property="Width" Value="150"/>
</Style>

If you run the project, you should see something like this :

image

The last thing we need to add is come data.  In order to do that, let’s add the following line to our MainPage code behind:

cbTest.ItemsSource = Product.GetProducts();

Running our project again, you should now have data.  Selecting an item should update the Selected Item text.

image

Now the we have our project set up, how can we disable individual items?  The default Item container for a CombBox is the CombBoxItem.  That means that for every item that you create, regardless if you are using the DisplayMemberPath or a custom ItemTemplate, is set inside a ComboBoxItem.  It just so happens that the ComboBoxItem object has an IsEnabled property that we can use to enable/disable the items.

Prior to Silverlight 5, there were several ways of attacking this problem, however Silverlight 5 offers a much simpler approach.  On day 6 of my 12 Days of Silverlight series I talked about the new Silverlight 5 feature of Binding in Style setters.  So how about we show this new feature in action?

We can use the new binding feature to make using the IsEnabled property a snap.  Let’s add the following Style settings to our User.Resources.

<Style TargetType="ComboBoxItem">
    <Setter Property="IsEnabled" Value="{Binding IsAvailable}"/>
</Style>

Now the IsEnabled property of the ComboBoxItem will be triggered off of our IsAvailable Product property.  Yep, it’s that easy.  Let’s rerun our application and see what we have.  If you expand the ComboBox, you will notice that the Clamp item is greyed out and you cannot select it.  And you thought you wouldn’t use binding in Style setters.  Tisk tisk…

image

This post was really about two things.  The first was to solve the direct problem of disabling items in your ComboBox.  The second was to give a real life example of using the binding in Style setters.

You can download the code for the project : SL5ComboBoxItemEnabled.zip

Leave a Reply