can't clear WPF ListBox.SelectedItems collection
Asked Answered
M

1

7

I can't seem to get the SelectedItems collection of a data bound WPF ListBox to clear. I've tried calling ListBox.SelectedItems.Clear(), i've tried setting the SelectedIndex to -1, setting the SelectedItem to null and calling ListBox.UnselectAll(). While debugging it appears that either the assignments don't take or something is resetting the SelectedItems collection, but I'm not sure what. I put a breakpoint in the SelectionChanged callback and it never gets hit unexpectedly yet the SelectedItems.Count member is always at least 1 (sometimes more than 1 since this ListBox's selection mode is MultiExtended).

Has anyone seen this before and know what I'm doing wrong? This question is seemingly exactly the same as this one: WPF - How to clear selection from ListView?

except in that post, Sonny Boy is using a ListView and I'm using a ListBox. In any case, the voted upon answer was to call ListView.UnselectAll() which doesn't work in my case.

I feel like I must be doing something very obviously wrong as clearing the selection should be pretty straight forward.

NOTE: Just to be clear, I don't want to remove the selections from the ListBox, I just want nothing to be selected.

thanks!

                            <ListBox Background="{StaticResource ResourceKey=DarkGray}" Name="lbx_subimageThumbnails" Margin="6,6,6,0" ItemsSource="{Binding ElementName=lbx_thumbnails, Path=SelectedItem.Swatches}" Style="{StaticResource WPTemplate}" SelectionMode="Extended" Height="{Binding ElementName=sld_swatchRows, Path=Value}" VerticalAlignment="Top" SelectionChanged="lbx_subimageThumbnails_SelectionChanged" DataContext="{Binding}">
                            <ListBox.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapPanel HorizontalAlignment="Stretch" />
                                </ItemsPanelTemplate>
                            </ListBox.ItemsPanel>
                            <ListBox.ItemContainerStyle>
                                <Style TargetType="{x:Type ListBoxItem}">
                                    <Setter Property="Visibility" Value="{Binding Path=Vis}" />
                                </Style>
                            </ListBox.ItemContainerStyle>
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                    <Grid Width="270" Height="270" Margin="5,5,5,5" Tag="{Binding}" Name="lbx_swatchThumbnail" Background="{StaticResource ResourceKey=LightGray}" PreviewMouseLeftButtonDown="lbx_swatchThumbnail_PreviewMouseLeftButtonDown" PreviewMouseMove="lbx_swatchThumbnail_PreviewMouseMove">
                                        <Grid.LayoutTransform>
                                            <ScaleTransform CenterX="0" CenterY="0" ScaleX="0.50" ScaleY="0.50" />
                                        </Grid.LayoutTransform>
                                        <Grid.ContextMenu>
                                            <ContextMenu>
                                                <MenuItem Header="Sync selected" Click="btn_syncSwatch_Click" />
                                                <MenuItem Header="Re-export selected" Click="btn_exportSelected_Click"/>
                                                <MenuItem Header="Set as default thumbnail" Click="btn_setThumbnail_Click"/>
                                                <MenuItem Header="Delete selected" Click="btn_deleteSwatch_Click"/>
                                                <MenuItem Header="Show in Explorer" Click="mnu_showSwatchesInExplorer_Click" />
                                                <MenuItem Header="Create Frames" Click="mnu_createFrames_Click" ToolTip="Creates FRAMEs groups to your PSD file under the Group associated with the selected swatch. DO NOT RE-ORDER OR RENAME THE GENERATED groups!" />
                                                <MenuItem Header="Create MIPs" Click="mnu_createMIPs_Click" ToolTip="Creates MIPs groups to your PSD file under the Group associated with the selected swatch. DO NOT RE-ORDER OR RENAME THE GENERATED groups!" />
                                            </ContextMenu>
                                        </Grid.ContextMenu>
                                        <Border BorderBrush="Black" BorderThickness="1">
                                            <Grid ToolTip="{Binding Path=Texture}">
                                                <Image VerticalAlignment="Center" HorizontalAlignment="Center" PhotoLoader:Loader.DisplayOption="Preview" PhotoLoader:Loader.DisplayWaitingAnimationDuringLoading="True" PhotoLoader:Loader.Source="{Binding Path=Texture}" PhotoLoader:Loader.DisplayErrorThumbnailOnError="True" Width="256" Height="256" />
                                                <TextBlock VerticalAlignment="Top" HorizontalAlignment="Center" Margin="0,10,0,0" FontSize="20"  Text="{Binding Path=Group}" Background="Black" Foreground="White"/>
                                                <TextBlock VerticalAlignment="Bottom"  HorizontalAlignment="Center" Background="Black" Margin="0,0,0,10" FontSize="20" Foreground="White">
                                                    <TextBlock.Text>
                                                        <MultiBinding StringFormat="{}{0} x {1} {2}" >
                                                            <Binding Path="Width" />
                                                            <Binding Path="Height" />
                                                            <Binding Path="Format" />
                                                        </MultiBinding>
                                                    </TextBlock.Text>
                                                </TextBlock>
                                            </Grid>
                                        </Border>
                                    </Grid>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                        </ListBox>


        // this callback kicks everything off. 
        private void btn_editSwatch_Click(object sender, RoutedEventArgs e)
        {
            // get a list of the selected indices - we will have to unselect the texture source and reselect it after the re-export in order to force the thumbnail display to update
            // so we will save a list of indices to reselect them after the export
            List selectedIndices = new List();
            for (int i = 0; i < lbx_subimageThumbnails.Items.Count; i++)
            {
                if (lbx_subimageThumbnails.SelectedItems.Contains(lbx_subimageThumbnails.Items[i]))
                {
                    selectedIndices.Add(i);
                }
            }

        // store the index of the selected texture source to reselect it after the re-export
        int selIndex = lbx_thumbnails.SelectedIndex;

        // edit and re-export the selected thumbnails
        if (this.EditThumbnails(lbx_subimageThumbnails.SelectedItems, lbx_thumbnails.SelectedItem))
        {

            // re-select the texture source
            lbx_thumbnails.SelectedIndex = selIndex;

            // re-select the previously selected thumbnails.
            foreach (int index in selectedIndices)
            {
                if (!lbx_subimageThumbnails.SelectedItems.Contains(lbx_subimageThumbnails.Items[index]))
                {
                    lbx_subimageThumbnails.SelectedItems.Add(lbx_subimageThumbnails.Items[index]);
                }
            }
        }
    }

    private void lbx_subimageThumbnails_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ListBox textureSelector = sender as ListBox;
        if (textureSelector != null)
        {
            //update some UI elements
        }
    }

    /*
    this is the SelectionChanged callback for another listbox which is bound as the ItemSource of lbx_subimageThumbnails. When the selection here changes, we default the selection of the subimage listbox to the first subimage after first clearing the selected items in the subimage listbox
    */
    private void lbx_thumbnails_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        // clear the previous swatch selection and select the first thumbnail
        // None of these methods works. after each, lbx_subimageThumbnails.SelectedItems.Count is still >= 1
        // Also, trying to set the SelectedIndex doesn't take. After the assignment, debugger shows                          
        // SelectedIndex is still 0 
        lbx_subimageThumbnails.SelectedIndex = -1;
        lbx_subimageThumbnails.SelectedIndex = -1;

        // Trying to set SelectedItem to null doesn't work...after assignment, SelectedItem is still a vaild
        // reference
        this.lbx_subimageThumbnails.SelectedItem = null;
        if (lbx_subimageThumbnails.SelectedItems.Count > 0)
        {
            lbx_subimageThumbnails.UnselectAll();
            lbx_subimageThumbnails.SelectedItems.Clear();
        }

        lbx_subimageThumbnails.SelectedIndex = 0;

        // reset the preview pane size
        sld_previewSize.Value = 1.0;
    }

Monochrome answered 24/4, 2013 at 1:40 Comment(5)
Please post your Xaml and code here. Without the code we cannot get the full idea.Antigone
Have you tried the SetSelectedItems method on the ListBox?Salvo
@Antigone - updated the post to include the relevant XAML and c# codeMonochrome
@Andrew: The ListBox object doesn't appear to have a SetSelectedItems method. I see it listed in MSDN, but Intellisense doesn't pull it up and the compiler doesn't think that method is a member of the Listbox class for some reason.Monochrome
I've gone ahead and cleared the ListBox via lbx_subimageThumbnails.ItemsSource = null; so now Items.Count is 0, but there's STILL an object in the SelectedItems collection. What is the relationship between Listbox.Items and Listbox.SelectedItems? I thought SelectedItems was a subset of Items, but apparently that's not the case...? I have no idea where this mystery object came from that is apparently in the Listbox's Items collection. I'm not very experienced debugging managed code...is there a good way to track down where this object came from?Monochrome
P
12

Have you overidden Equals() and GetHashCode() on the items in the ListBox? I can replicate this by:

  1. Selecting an item in the list.
  2. Changing a property on the item that results in a change to it's hashcode.
  3. Selecting a different item.

The first item is not removed from SelectedItems and cannot be removed manually the in way you describe. This is the case even when SelectionMode is single, and will result in an exception being thrown should you re-select the first item.

Penetrance answered 3/6, 2013 at 14:27 Comment(3)
Thank you! I spent two days trying to track this down (both the exception and not being able to change SelectedItems, in a DataGrid rather than a ListBox) and this is exactly right and let me fix it immediately.Paddock
This was a diamond in the rough... who would've thought! Same thing happened with DataGrid in my case as well. Brilliant!Stringfellow
Had the same root cause, but different scenario, so adding a quick comment in case someone else has the same issue. Issue: Clicking between items following a drag and drop was causing an assert that couldn't be trapped in a try catch, and call stack was not helpful. Cause: On move a property for index + 1 was being updated, and that property was included in the equals/hashcode. Solution: Replace index related property in equals and hashcode with unique identifierMaimonides

© 2022 - 2024 — McMap. All rights reserved.