Mark A. Donohoe
Mark A. Donohoe

Reputation: 30488

How can you disallow an item in a ListBox from being selected?

We're trying to create a ListBox which has a few items inside that the user cannot select. Think the group headings in a grouped listbox, except these are independent items (i.e. no indented children.) We just want to display a message in the list.

Here's a mock-up of what we currently display if there are 'Foo' items...

Foo 1
Foo 2
Foo 3
--------------   <-- This is of type 'Separator' so it's styled as not-selectable by default.
Add new Foo...
Manage Foos...

...and if there aren't any Foo items, we display this...

[No Foo Items]   <-- This one should not be selectable, the same as a separator
--------------   <-- This is of type 'Separator' so it's styled as not-selectable by default.
Add new Foo...
Manage Foos...

Now again, we already have the code that properly handles what's displayed (see below). We're wondering what's the proper way to disable that entry from being able to be selected.

What we don't know is how to style that ListBoxItem so the selection skips right over it, nor can the user click on it.

Code

Someone asked me to see my code, so here it is. Not really relevant to the question, but should show people how I did this.

Note: We template the string.Empty in the XAML to show the localized 'No xxx Items' message. string.Empty is just a placeholder that we can target.

Note 2: FauxData is a simple library of items and collections used for testing so I don't have to constantly create them from scratch. SimpleItemCollection for instance creates ten SimpleItem objects in the constructor, pre-populated with things like Name, Description, IsSelected, etc. all fully supporting INotifyPropertyChanged and collection change notifications. I have the same thing with HierarchicalItemsCollection which adds Parent, Children and IsExpanded, etc. It saves a LOT of work when testing code and controls!

Finally, this is from a simple test, or 'playground' app. As such, it's not supposed to represent the best way to do things, just to show a concept. Yes, it can be cleaned up a lot, but you get the general idea.

Anyway, on to the code...

using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using FauxData;

namespace Playground.ListTest
{
    [LaunchEntry("List Test")]
    public partial class Main : Window
    {
        SimpleItemCollection itemsCollection = new SimpleItemCollection(); // Default constructor creates 10 items

        public Main()
        {
            InitializeComponent();
            MainListBox.ItemsSource = CreateCompositeCollection();
        }

        private CompositeCollection CreateCompositeCollection()
        {
            var EmptyHolder = new ObservableCollection<object>();

            itemsCollection.CollectionChanged += (s,e) => {

                if(itemsCollection.Count != 0)
                    EmptyHolder.Clear();
                else if(EmptyHolder.Count == 0)
                    EmptyHolder.Add(string.Empty);

            };

            var cc = new CompositeCollection();

            cc.Add(new CollectionContainer(){ Collection = itemsCollection });
            cc.Add(new CollectionContainer(){ Collection = EmptyHolder });
            cc.Add(new Separator());
            cc.Add(ApplicationCommands.New);   // <-- Pops a dialog to enter a new item
            cc.Add(ApplicationCommands.Open);  // <-- Shows an item management window

            return cc;

        }

        private void Test_Click(object sender, RoutedEventArgs e)
        {
            if(itemsCollection.Count != 0)
                itemsCollection.Clear();
            else
                itemsCollection.Add(new SimpleItem(){Name = "New item" });
        }

    }

}

Upvotes: 2

Views: 5718

Answers (3)

paparazzo
paparazzo

Reputation: 45106

If you don't want it to gray out then IsHitTestVisible seems to achieve that.

    <ListBox SelectionMode="Multiple">
        <ListBoxItem IsEnabled="False">HEsder</ListBoxItem>
        <ListBoxItem IsEnabled="True">1</ListBoxItem>
        <ListBoxItem IsHitTestVisible="False">-----</ListBoxItem>
        <ListBoxItem IsEnabled="True">2</ListBoxItem>
    </ListBox>

If you are Binding the you would need to user a trigger.

Upvotes: 1

brunnerh
brunnerh

Reputation: 185553

As Focusable="false" does not cover all options (e.g. click and drag select) i would recommend setting IsEnabled to false instead.

(The greyed out text is a matter of the ListBoxItem style/template, so if you do not like it you will need to override it)

Upvotes: 3

Mark A. Donohoe
Mark A. Donohoe

Reputation: 30488

Wow! That was easy! On the ListBoxItem you want to skip, you just set Focusable to False.

Done and done!

Upvotes: 1

Related Questions