KirillOsenkov / PublicBugs

My personal bug tracker for products where it's not worth logging a bug in their tracker
MIT License
0 stars 0 forks source link

WPF ListBox moves focus to ListBox after item deleted #20

Open KirillOsenkov opened 3 years ago

KirillOsenkov commented 3 years ago

Have a ListBox that can delete selected item.

Verify an item is both selected and focused (not the listbox itself), delete it by showing a confirmation dialog.

When the dialog is dismissed and the item is deleted, the selected item is correctly updated to the next item, but the focus returns to the ListBox itself (apparently because the item is gone).

So the focus and selection are dissynchronized, selection remains in the right place, but the focus switches to the parent listbox, so pressing Up or Down will just switch both the focus and the selection to the first element instead of navigating to the previous/next element.

KirillOsenkov commented 3 years ago

https://social.msdn.microsoft.com/Forums/vstudio/en-US/65d15647-733d-4701-8559-6a058491b844/listboxfocus-resets-selected-item-to-0th-on-next-cursor-press?forum=wpf

KirillOsenkov commented 3 years ago

image

KirillOsenkov commented 3 years ago
    PresentationCore    UIElement.Focus Line 2630
    PresentationFramework   ListBoxItem.OnVisualParentChanged Line 359
    PresentationCore    Visual.FireOnVisualParentChanged Line 4000
    PresentationCore    Visual.RemoveVisualChild Line 2735
    PresentationCore    Visual.InternalRemoveVisualChild Line 2598
    PresentationCore    VisualCollection.DisconnectChild Line 468
    PresentationCore    VisualCollection.RemoveRange Line 830
    PresentationFramework   UIElementCollection.RemoveRangeInternal Line 369
    PresentationFramework   VirtualizingPanel.RemoveInternalChildRange Line 512
    PresentationFramework   VirtualizingStackPanel.RemoveChildRange Line 8987
    PresentationFramework   VirtualizingStackPanel.OnItemsRemove Line 8936
    PresentationFramework   VirtualizingStackPanel.OnItemsChanged Line 3596
    PresentationFramework   VirtualizingPanel.OnItemsChangedInternal Line 581
    PresentationFramework   Panel.OnItemsChanged Line 686
    PresentationFramework   ItemContainerGenerator.OnItemRemoved Line 2583
    PresentationFramework   ItemContainerGenerator.OnCollectionChanged Line 2420
KirillOsenkov commented 3 years ago

https://github.com/dotnet/wpf/blob/1ea14f8b6a4e825bb575918dec498dd304c4fd8b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ListBoxItem.cs#L355-L360

KirillOsenkov commented 3 years ago

Selection works correctly because it operates on the view, not on the ListBox itself:

See ListCollectionView.MoveCurrencyOffDeletedElement

    PresentationFramework   Selector.OnSelectionChanged Line 1323
    PresentationFramework   ListBox.OnSelectionChanged Line 287
    PresentationFramework   Selector.InvokeSelectionChanged Line 1804
    PresentationFramework   Selector.SelectionChanger.End Line 2369
    PresentationFramework   Selector.SelectionChanger.SelectJustThisItem Line 2708
    PresentationFramework   Selector.SetSelectedToCurrent Line 1568
    PresentationFramework   Selector.OnCurrentChanged Line 1489
    PresentationFramework   CollectionView.OnCurrentChanged Line 1066
    PresentationFramework   ItemCollection.OnCurrentChanged Line 1932
    WindowsBase WeakEventManager.ListenerList`1.DeliverEvent
    WindowsBase WeakEventManager.DeliverEventToList
    WindowsBase WeakEventManager.DeliverEvent
    WindowsBase CurrentChangedEventManager.OnCurrentChanged
    PresentationFramework   CollectionView.OnCurrentChanged Line 1066
    PresentationFramework   ListCollectionView.MoveCurrencyOffDeletedElement Line 2669
    PresentationFramework   ListCollectionView.ProcessCollectionChangedWithAdjustedIndex Line 2154
    PresentationFramework   ListCollectionView.ProcessCollectionChanged Line 1837
    PresentationFramework   CollectionView.OnCollectionChanged Line 1186
KirillOsenkov commented 3 years ago

Workaround:

        // Workaround for https://github.com/KirillOsenkov/PublicBugs/issues/20
        private void CurrentFoldersAndFilesView_CurrentChanged(object sender, EventArgs e)
        {
            if (Keyboard.FocusedElement == fileListBox && fileListBox.SelectedItem is { } selectedItem)
            {
                if (fileListBox.ItemContainerGenerator.ContainerFromItem(selectedItem) is { } itemContainer && itemContainer is FrameworkElement frameworkElement)
                {
                    Keyboard.Focus(frameworkElement);
                }
            }
        }
KirillOsenkov commented 3 years ago

Workaround for TreeView:

        public void MoveSelectionOut()
        {
            var parent = Parent;
            if (parent == null)
            {
                return;
            }

            var next = parent.FindNext<SelectableViewModel>(this);
            if (next != null)
            {
                IsSelected = false;
                next.IsSelected = true;
                return;
            }

            var previous = parent.FindPrevious<SelectableViewModel>(this);
            if (previous != null)
            {
                IsSelected = false;
                previous.IsSelected = true;
            }
            else
            {
                IsSelected = false;
                parent.IsSelected = true;
            }
        }