Search code examples
.netwpflistboxselecteditem

How to ensure that no item is selected in databound ListBox?


OK, this must be a duplicate question, but I cannot find the answer: I have a listbox that is databound to a Collection. By default Items[0] is selected. How can I prevent this in order to ensure that the SelectionChanged event is raised any time I click a ListBoxItem?

EDIT: I had already dismissed the SelectedIndex=-1 route, but I tried again: Setting the SelectedIndex to -1 in the Listbox's constructor (or as an attribute in XAML) does not work. It seems that the listbox is populated after the initialization and the selectedindex will become 0 after all.Same story for setting the SelectedItem to null;

I tried this:

<ListBox ItemsSource="{Binding Value}" 
         SelectionChanged="ListBox_SelectionChanged"
         IsSynchronizedWithCurrentItem="True"
         Loaded="ListBox_Loaded">
</ListBox>

with:

 private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if(e.AddedItems.Count==0)return;//Prevents stackoverflow! ;-)
        ((ListBox)e.OriginalSource).SelectedItem=null;
    }

private void ListBox_Loaded(object sender, RoutedEventArgs e)
{
    ((ListBox) sender).SelectedItem = null;
}

This works, BUT it inserts a blank line on top of the items that the listbox displays, which is very ugly.... In my particular case I could solve the problem by removing the IsSynchronizedWithCurrentItem attribute.

But I can think of many scenarios in which this would not be acceptable.

The above statement is nonsense: either you want to make use of master-detail binding and set the IsSynchronizedWithCurrentItem to true, or you don't. It is rather unlikely that you want to make use of master-detail binding and then have no currently selected item in your listbox all the time


Solution

  • Use CollectionView as an ItemsSource for your list box. A fresh WPF project with no item initially selected:

    XAML:

    <Window x:Class="ListBoxDataBinding.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <ListBox 
            ItemsSource="{Binding Path=Value, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" 
            SelectionChanged="ListBox_SelectionChanged"
            IsSynchronizedWithCurrentItem="True"
            >
        </ListBox>
    </Grid>
    </Window>
    

    cs:

    public partial class Window1: Window {
        public IEnumerable Value {
            get { return (IEnumerable)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
    
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(IEnumerable), typeof(Window1), new UIPropertyMetadata(null));
    
    
        public Window1() {
            InitializeComponent();
            var view = new TheCollectionView();
            view.MoveCurrentTo(null);
            this.Value = view;
        }
    
        private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            MessageBox.Show("Selection changed");
        }
    }
    
    public class TheCollectionView: CollectionView {
        public TheCollectionView(): base(new TheCollection()) {
        }
    }
    
    public class TheCollection: List<string> {
        public TheCollection() {
            Add("string1");
            Add("string2");
            Add("string3");
        }
    }