How To - Default Text on WPF Combo Boxes

When you want to add a default text (i.e. Please Select/ Select Item etc.) to a ComboBox in WPF, there is a easier way to do it. Take a look at the code below.

 <ComboBox Name="comboBox1"            
          Text="--Select Item--"
          IsEditable="true"
          IsReadOnly="true"/> 
This works. You get a nice "--Select Item--" on the combo box but the problem is, the ComboBox is editable. I don't want this behavior. I want the default text to appear in an uneditable combo box. Like this,


StackOverFlow is our friend. There is a much better answer using a Combo Box Behavior. But in this code, there is a small problem.

 public static readonly DependencyProperty DefaultTextProperty =
        DependencyProperty.RegisterAttached("DefaultText", typeof(String), typeof(ComboBox), new PropertyMetadata(null));
Note the ComboBox in 3rd parameter. This causes an issue when used in more than one combo box. 'DefaultText' Property already registered by 'ComboBox'. 

So the fix would be to mention ComboBoxBehaviors as the 3rd Parameter and attach a method to hookup the combobox behavior to any combo box which is using our Default Text behavior.

public static class ComboBoxBehaviors
    {
        public static readonly DependencyProperty DefaultTextProperty =
            DependencyProperty.RegisterAttached("DefaultText", 
                  typeof(String), 
                  typeof(ComboBoxBehaviors), 
                  new PropertyMetadata(null, HookupBehavior));

        public static String GetDefaultText(DependencyObject obj)
        {
            return (String)obj.GetValue(DefaultTextProperty);
        }

        private static void HookupBehavior(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            ComboBox combo = d as ComboBox;
            if (combo == null) return;

            SetDefaultText(d, e.NewValue.ToString());
        }

        public static void SetDefaultText(DependencyObject obj, String value)
        {
            var combo = (ComboBox)obj;

            RefreshDefaultText(combo, value);

            combo.SelectionChanged += (sender, _) => RefreshDefaultText((ComboBox)sender, GetDefaultText((ComboBox)sender));

            obj.SetValue(DefaultTextProperty, value);
        }

        static void RefreshDefaultText(ComboBox combo, string text)
        {
            // if item is selected and DefaultText is set
            if (combo.SelectedIndex == -1 && !String.IsNullOrEmpty(text))
            {
                // Show DefaultText
                var visual = new TextBlock()
                {
                    FontStyle = FontStyles.Italic,
                    Text = text,
                    Foreground = Brushes.Gray
                };

                combo.Background = new VisualBrush(visual)
                {
                    Stretch = Stretch.None,
                    AlignmentX = AlignmentX.Left,
                    AlignmentY = AlignmentY.Center,
                    Transform = new TranslateTransform(3, 0)
                };
            }
            else
            {
                // Hide DefaultText
                combo.Background = null;
            }
        }
    }

You can use it like this:

<UserControl x:Class="Samples.WPF.MyView" 
             ....

xmlns:behaviors="clr-namespace:Samples.WPF.Behaviors"

.... d:DesignHeight="300" d:DesignWidth="300"> <ComboBox Name="BillCyclesComboBox" ItemsSource="{Binding BillCycles}"

behaviors:ComboBoxBehaviors.DefaultText="-- Please Select --"

DisplayMemberPath="Description" SelectedValuePath="ID" SelectedItem="{Binding Path=SelectedBillCycle}" /> ... </UserControl>

Popular posts from this blog

Print a receipt using a Thermal Printer with C#.NET

Automatic redirect upon session timeout using ASP.NET MVC and Javascript

Complex Master-Detail Form using Knockout.js and ASP.NET MVC