Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF Disabled Items Behaviour

0.00/5 (No votes)
6 Aug 2016 1  
This tip presents a way to have disabled items in your ComboBox

Introduction

It was requested that some items in a ComboBox list would not be selectable. This proved to be a much more difficult task than I expected. IsHitTestVisible and IsEnabled for a control used in the ItemTemplate did not work.

Design

I initially started testing in the OnSelectionChanged event, and then moved to a generic, and finally a behaviour:

 public class ComboBoxItemAvailableBehaviour
 {
  public static readonly DependencyProperty IsAvailableProperty =
   DependencyProperty.RegisterAttached("IsAvailable", typeof(Func<object,bool>),
    typeof(ComboBoxItemAvailableBehaviour), new UIPropertyMetadata(null, OnValueChanged));

  public static Func<object, bool> GetIsAvailable(Control o)
  {
   return (Func<object, bool>)o.GetValue(IsAvailableProperty);
  }

  public static void SetIsAvailable(Control o, Func<object, bool> value)
  {
   o.SetValue(IsAvailableProperty, value);
  }

  private static void OnValueChanged(DependencyObject dependencyObject,
   DependencyPropertyChangedEventArgs e)
  {
   var comboBox = dependencyObject as ComboBox;
   if (comboBox != null)
   {
    comboBox.SelectionChanged -= ComboBox_SelectionChanged;
    comboBox.SelectionChanged += ComboBox_SelectionChanged;
   }
  }

  private static void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
  {
   var comboBox = (ComboBox)sender;
   if (e.AddedItems.Count > 0)
   {
    if (! GetIsAvailable(comboBox).Invoke(e.AddedItems[0]))
     if (e.RemovedItems.Count > 0)
      comboBox.SelectedItem = e.RemovedItems[0];
     else
      comboBox.SelectedIndex = -1;
   }
  }
 }

The DependencyProperty is of type Func<object,bool> so that any value can be passed to the behavior for evaluation. This Func<object,bool> is used to determine if the DataContext for the particular ComboBoxItem is selectable. When a new Func<object,bool> is provided, a subscription is made to the SelectionChanged event. When the selection is changed, checking for any added item is made, and if there is an added item, the function is called to check if this is an item is available. If it is not available, the change is backed out. This could mean that the SelectedItem is set back to the removed item, or the SelectedIndex is set to -1 if there are no removed items.

In the OnValueChanged method, before there is s subscription to the SelectionChanged event, there is a remove to ensure that there is not a multiple subscription to the event. Probably unnessary since this behaviour will probably not change, but method to be used to check if the item is availble could be updated.

Using the Code

To use the code, a property of type Func<object, bool> has to be in the DataContext. This is bound to the IsAvailable DependencyProperty of the behaviour:

<ComboBox Width="100"
          HorizontalAlignment="Center"
          VerticalAlignment="Center" SelectionChanged="Selector_OnSelectionChanged"
     local:ComboBoxItemAvailableBehaviour.IsAvailable="{Binding IsAvailable}"
          ItemsSource="{Binding ItemsSource}"
          SelectedItem="{Binding SelectedItem}">
 <ComboBox.ItemTemplate>
  <DataTemplate DataType="{x:Type local:ComboBoxItemViewModel}">
   <TextBlock Foreground="{Binding IsAvailable,
                                   Converter={local:IsTrueConverter},
                                   ConverterParameter=Black:Gray}"
              IsHitTestVisible="False"
              Text="{Binding Text}" />
  </DataTemplate>
 </ComboBox.ItemTemplate>
</ComboBox>

History

  • 08/05/2016: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here