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

北战南征 提交于 2019-12-05 16:24:59

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");
    }
}

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.

listbox.selectedIndex = -1

That should de-select everything (since index -1 doesn't exist), but as far as I'm aware unless you explicitly set the default selectedItem the listview is generated with nothing selected, so it's possible that SelectedIndex has been inadvertently set at some point. Note that SelectedIndex can be set in XAML as well.

You need to set the Index to -1, this tells the listbox not to select anything. In the SelectionChanged Event, set the listbox's Index property to -1.

Hope this helps, Best regards, Tom.

How about dumping the SelectionChanged event handler and data binding a dependency property or notifying property to the SelectedValue instead?

You can use the Tap event instead of SelectionChanged:

<ListBox  ItemsSource="{Binding Data}" Tap="ListBox_Tap" ... />
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!