Silverlight ComboBox Prompt text if an item isn’t selected

If you work with Silverlight you can notice that default ComboBox displays empty text if it doesn’t have a selected item.

This behaviour is far from the expected, and one of the workaround is to select the first item from the list. It is good, but it can’t be used in every situation.

So I extended the default control and now it has the following features:

1. Displays a prompt if a user hasn’t selected an item.

2. Displays a prompt if the combobox doesn’t have items at all.

To achieve this I handle only two events:

  • SelectionChanged – to add or remove the “Select Item…” prompt if it is necessary.
  • OnItemsChanged – to add or remove the “No Items…” promptif it is necessary.

Here is complete source code with comments:

    [TemplateVisualState(Name = ExtendedComboBox.StateNormal, GroupName = ExtendedComboBox.GroupItemsSource)]
    [TemplateVisualState(Name = ExtendedComboBox.StateNotSelected, GroupName = ExtendedComboBox.GroupItemsSource)]
    [TemplateVisualState(Name = ExtendedComboBox.StateEmpty, GroupName = ExtendedComboBox.GroupItemsSource)]
    public class ExtendedComboBox : ComboBox
    {
        public const string GroupItemsSource = "ItemsSourceStates";
        public const string StateNormal = "Normal";
        public const string StateNotSelected = "NotSelected";
        public const string StateEmpty = "Empty";

        private ContentPresenter selectedContent;

        public ExtendedComboBox()
        {
            this.DefaultStyleKey = typeof(ComboBox);
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.selectedContent = this.GetTemplateChild("ContentPresenter") as ContentPresenter;

            //this event can change the NotSelected state
            this.SelectionChanged += (s, e) => this.SetTextIfEmpty();

            //Set a state at start
            this.SetTextIfEmpty();
        }

        //this method can change the Empty state
        protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            this.SetTextIfEmpty();
        }

        /// <summary>
        /// Text if the SelectedItem is null
        /// </summary>
        public string NotSelectedText
        {
            get { return (string)GetValue(NotSelectedTextProperty); }
            set { SetValue(NotSelectedTextProperty, value); }
        }

        public static readonly DependencyProperty NotSelectedTextProperty =
            DependencyProperty.Register("NotSelectedText", typeof(string), typeof(ExtendedComboBox), new PropertyMetadata(" "));

        /// <summary>
        /// Text if there is no items in the ComboBox at all
        /// </summary>
        public string EmptyText
        {
            get { return (string)GetValue(EmptyTextProperty); }
            set { SetValue(EmptyTextProperty, value); }
        }

        public static readonly DependencyProperty EmptyTextProperty =
            DependencyProperty.Register("EmptyText", typeof(string), typeof(ExtendedComboBox), new PropertyMetadata(null));

        /// <summary>
        /// Change the state of this control and updates displayed text
        /// </summary>
        protected void SetTextIfEmpty()
        {
            if (this.selectedContent == null || !(this.selectedContent.Content is TextBlock))
                return;
            var text = this.selectedContent.Content as TextBlock;

            if (this.SelectedItem == null && this.Items != null && this.Items.Count > 0)
            {
                text.Text = this.NotSelectedText;
                VisualStateManager.GoToState(this, ExtendedComboBox.StateNotSelected, true);
            }
            else if (this.SelectedItem == null)
            {
                text.Text = this.EmptyText ?? this.NotSelectedText;
                VisualStateManager.GoToState(this, ExtendedComboBox.StateEmpty, true);
            }
            else VisualStateManager.GoToState(this, ExtendedComboBox.StateNormal, true);
        }
    }

I’m not sure whether this control works with a tricky ItemTemplate, but at least it works in 99% of cases.

Complete example: ComboBoxWithPrompt.zip

Show case: Test Page

About these ads

12 Responses to Silverlight ComboBox Prompt text if an item isn’t selected

  1. Sibin says:

    Wonderful idea. Helped me a lot. can I know why you use ‘TemplateVisualState’ here ?

    • vortexwolf says:

      The `TemplateVisualState` attributes are not so necessary, but I think that they will be displayed in the Expression Blend, just near the built-in visual states. However, I’m not sure, I haven’t used the Expression Blend for a long time.

  2. Mike D says:

    Thank’s for the post. Much nicer than the hacks I’ve come accros. I’m new to SL, My demo app apply’s an SL theme based upon user settings. Would you know how to apply the current app theme to the combobox?

    • vortexwolf says:

      I worked with Theming in Silverlight, so I know much about it. You can send me an e-mail message or ask the question on StackOverflow and post the link here.

  3. mozofuck says:

    Maybe it’s a noob question but i can’t see the ExtendedComboBox.xaml in your project, and i think i need it to implement your ExtendedComboBox in my project.

    By the way, thx for sharing

  4. L says:

    Did you test the ExtendedCombo with SL5? Does it work?

    • vortexwolf says:

      Just tested: changed the Target Silverlight Version in the project settings to Silverlight5. No problems, works as well as with Silverlight4.

  5. It’s a great piece of work. But what if we want the end user to able to reselect the default option, kinda re-set the combobox with the default text.

    • vortexwolf says:

      You should add a separate button and use a code like `this.comboBox.SelectedItem = null;`. Set the `SelectedItem` property to null.

      • Thank you for your reply. Another question, what am I supposed to change in the source code to make it work in a WPF application project? Actually I tried the ExtendedComboBox in WPF but it isn’t working. Please bear with me as I am a newbie in Silverlight and WPF.

      • vortexwolf says:

        In order to make it work in WPF, try to change the code `this.GetTemplateChild(“ContentPresenter”)` to `this.GetTemplateChild(“ContentSite”). You should find out the name of the control where the text is situated.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: