Showing non-selectable items in a WPF ComboBox

This is a demo about adding non-selectable items (like titles or category names) and hyperlinks to a WPF ComboBox.

One way of dealing with large comboboxes is filtering. Another technique is proposing only the most popular items in the default list, and provide a hyperlink to the full list:



If the hyperlink is clicked, the ComboBox is entirely populated, but by adding non-selectable items you can still make the distinction:



Here's the full code for the demo:

XAML

<Window x:Class="DockOfTheBay.SuggestionComboBoxSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DockOfTheBay"
        Title="Suggestion ComboBox" 
        Height="120" Width="300">
    <StackPanel Orientation="Horizontal" 
                VerticalAlignment="Top"
                Margin="10 10">
        <TextBlock Text="Select: " 
                   Padding="4 3"/>
        <ComboBox 
            x:Name="SuggestionComboBox1" 
            Padding="4 3" 
            MinWidth="200"/>
    </StackPanel>
</Window>


C#

namespace DockOfTheBay
{
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Media;
 
    /// <summary>
    /// Demonstration of using non-selectable items and hyperlinks in a
    /// WPF ComboBox.
    /// </summary>
    public partial class SuggestionComboBoxSample : Window
    {
        /// <summary>
        /// The hyperlink displayed after the the ComboBox's Suggestions.
        /// </summary>
        private ComboBoxItem linkItem;
 
        /// <summary>
        /// Initializes a new instance of the SuggestionComboBoxSample class.
        /// </summary>
        public SuggestionComboBoxSample()
        {
            InitializeComponent();
 
            // Add an item that looks like a title
            ComboBoxItem item = new ComboBoxItem();
            item.Content = "Most Frequent";
            item.IsEnabled = false;
            item.Background = Brushes.Blue;
            item.Foreground = Brushes.White;
            SuggestionComboBox1.Items.Add(item);
 
            // Add suggestions
            foreach (var name in this.Suggestions())
            {
                SuggestionComboBox1.Items.Add(name);
            }
 
            // Don't add content directly, like the following:
            // SuggestionComboBox1.Items.Add(new Separator());
            // It will not display properly when databinding is used.
            item = new ComboBoxItem();
            item.Content = new Separator();
            SuggestionComboBox1.Items.Add(item);
            Hyperlink link = new Hyperlink();
 
            // 'RequestNavigate' is not fired, so use 'Click' instead
            link.Click += this.Link_Click;
 
            link.Inlines.Add(new Run("Show Everything"));
            item = new ComboBoxItem();
            item.Content = link;
            this.linkItem = item;
            SuggestionComboBox1.Items.Add(item);
        }
 
        /// <summary>
        /// Fetches the remaining items, and adds them to the ComboBox.
        /// </summary>
        /// <param name="sender">The HyperLink.</param>
        /// <param name="e">The Event Arg.</param>
        private void Link_Click(object sender, RoutedEventArgs e)
        {
            // Remove Hyperlink
            SuggestionComboBox1.Items.Remove(this.linkItem);
 
            // Add an item that looks like a title
            ComboBoxItem item = new ComboBoxItem();
            item.Content = "The Rest";
            item.IsEnabled = false;
            item.Background = Brushes.Blue;
            item.Foreground = Brushes.White;
            SuggestionComboBox1.Items.Add(item);
 
            // Add suggestions
            foreach (var name in this.Rest())
            {
                SuggestionComboBox1.Items.Add(name);
            }
        }
 
        /// <summary>
        /// The Suggested Items.
        /// </summary>
        /// <returns>A list of Suggestions.</returns>
        private List<string> Suggestions()
        {
            List<string> names = new List<string>();
            names.Add("WPF rocks");
            names.Add("WCF rocks");
            names.Add("XAML is fun");
 
            return names;
        }
 
        /// <summary>
        /// The non-Suggested Items.
        /// </summary>
        /// <returns>A list of non-Suggestions.</returns>
        private List<string> Rest()
        {
            List<string> names = new List<string>();
            names.Add("WPF rules");
            names.Add("WCF rules");
            names.Add("WinForms not");
 
            return names;
        }
    }
}


Here's how the control looks like in a real-life application for cancer registration. It presents a list of the most probable histologic diagnoses, based on key words in the tumor location:

2 comments:

  1. This is not the correct method of doing this. The CollectionViewSource has built in grouping functionality that should be used instead.

    ReplyDelete
  2. If you want your ex-girlfriend or ex-boyfriend to come crawling back to you on their knees (even if they're dating somebody else now) you got to watch this video
    right away...

    (VIDEO) Get your ex back with TEXT messages?

    ReplyDelete