xyzzer / WinRTXamlToolkit

WinRT XAML Toolkit
Other
283 stars 66 forks source link

TreeView in Flyout, selection after Flyout closes #49

Open ivansp opened 6 years ago

ivansp commented 6 years ago

I am currently trying to use WinRT xaml ToolKit TreeView component since it is not supported in UWP natively.

TreeView is inside a button Flyout. When I press the button I want Flyout to appear so I can select an item from the tree. And I bind a command from ViewModel to SelectedItemChanged event:

<Button
   x:Name="btnFilter"
   HorizontalAlignment="Right"
   Command="{Binding OpenFiltersCommand}"
   Style="{StaticResource SecondaryMenuButtonStyle}">
   <StackPanel Orientation="Horizontal">
     <Image
       Width="28"
       Margin="0,0,4,0"
       Source="{StaticResource FilterIcon}" />
     <TextBlock x:Uid="Filter" Style="{StaticResource GrayTextBlockStyle}" />
   </StackPanel>
   <FlyoutBase.AttachedFlyout>
     <controls1:CustomFlyout IsOpen="{Binding IsFiltersOpen, Mode=TwoWay}" Parent="{Binding ElementName=btnFilter}">
        <controls2:TreeView
          ItemContainerStyle="{StaticResource DefaultTreeViewItem}"
          ItemTemplate="{StaticResource TreeViewItemTemplate}"
          ItemsSource="{Binding BuildingTree}"
          Style="{StaticResource DefaultTreeViewStyle}">
            <i:Interaction.Behaviors>
              <core:EventTriggerBehavior EventName="SelectedItemChanged">
                <core:InvokeCommandAction Command="{Binding ChangeRoomCommand}" />
              </core:EventTriggerBehavior>
            </i:Interaction.Behaviors>
         </controls2:TreeView>
      </controls1:CustomFlyout>
   </FlyoutBase.AttachedFlyout>
</Button>

After I select an item from TreeView, SelectedItemChanged event fires as it should, but afterwards I close the Flyout and the event fires again. The second time it usually fires saying new selected element is next after current's parent. So for example if I have this structure:


1
--1.0
--1.1
--1.2
2
--2.0
--2.1

So if I select --1.1 first SelectedItemChanged will fire with --1.1 element, and afterwards it will fire with 2 as new selected item.

Note: I am using CustomFlyout component which I can close from ViewModel, but I also tested this with regular Flyout and same thing happens after I close Flyout by clicking outside of it.

UPDATE: I've downloaded WinRT code and started debugging the TreeView component locally. In TreeViewItem.cs I've found the source of the problem in this function:

        protected override void OnGotFocus(RoutedEventArgs e)
        {
            // Since the GotFocus event will bubble up to the parent
            // TreeViewItem (which will make it think it's also selected), it
            // needs to ignore that event when it's first been handled by one of
            // its nested children.  We use the IgnoreNextGotFocus flag to
            // notify our parent that GotFocus has already been handled.
            TreeViewItem parent = ParentTreeViewItem;
            if (parent != null)
            {
                parent.CancelGotFocusBubble = true;
            }

            try
            {
                if (Interaction.AllowGotFocus(e) && !CancelGotFocusBubble)
                {
                    // Select the item when it's focused
                    Select(true);

                    // ActivateAsync the selection
                    IsSelectionActive = true;
                    UpdateVisualState(true);

                    Interaction.OnGotFocusBase();
                    base.OnGotFocus(e);
                }
            }
            finally
            {
                CancelGotFocusBubble = false;
            }            
        }

From what I can tell when element gets focus sometimes it fails to find it's parent and prevent propagating the event upwards in the tree.

Can anyone help me out with this issue?

xyzzer commented 6 years ago

Seems like you posted a workaround on SO: https://stackoverflow.com/questions/47968536/uwp-winrt-xaml-toolkit-treeview-in-flyout-changes-selection-after-flyout-clos/47976018#47976018

As I said previously it seems this is a bug in WinRT TreeView component however I managed to prevent (hard fix) this behavior by binding "IsEnabled" property to IsFiltersOpen property from my ViewModel. This way when I select my element I close the Flyout and disable TreeView component, which prevents it from updating.

ivansp commented 6 years ago

Yep sorry for late reply, wasn't sure if anyone was still checking issues on here. But yes, I inspected TreeView component locally and realized it was checking for IsEnabled property when updating selection so I binded that property to view models's IsFlyoutOpen.

Seems to solve the issue for my use case. Still it's kind of a "hard-fix" if you will.

xyzzer commented 6 years ago

A workaround is better than nothing and sometimes it's even better than a fix if the fix introduces new bugs... ;)