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

时光怂恿深爱的人放手 提交于 2019-12-07 07:56:49

问题


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


回答1:


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



回答2:


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.




回答3:


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.




回答4:


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.




回答5:


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




回答6:


You can use the Tap event instead of SelectionChanged:

<ListBox  ItemsSource="{Binding Data}" Tap="ListBox_Tap" ... />


来源:https://stackoverflow.com/questions/1790428/how-to-ensure-that-no-item-is-selected-in-databound-listbox

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