Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 370
Dabblernl Avatar asked Dec 13 '22 01:12

Dabblernl


2 Answers

After running a few tests, ListBox's default behavior is to not pre select an item in the list. Removing IsSynchronizedWithCurrentItem="True" will ensure the listbox doesn't start pre selected and the SelectionChanged event will be raised when the user clicks on any item.

If you do set IsSynchronizedWithCurrentItem to true it means the selectedIndex will always equal the index of the ListBox.Items.CurrentItem of ListBox.Items. ListBox.Items always has a CurrentItem and cannot be set to -1 or null due to CurrentItem or CurrentIndex being readonly.

Hope that helps J

edit... have just read

"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."

In which case i don't think it's possible for the reasons stated above.

like image 106
James Hay Avatar answered Dec 16 '22 18:12

James Hay


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");
    }
}
like image 28
Stanislav Kniazev Avatar answered Dec 16 '22 16:12

Stanislav Kniazev