Selected TreeViewItem bug when the TreeView is in a popup

Dec 5, 2014 at 11:15 AM
There's a bug in TreeView when it is in a popup. And here's a workaround.

What's wrong?
When closing the popup, the selected item is changed to the next not empty expanded branch in the root of the TreeView.

Steps to reproduce:
Step 1. Let's open the sample app that's coming with the toolkit (WinRTXamlToolkit.Sample).
Step 2. Open WinRTXamlToolkit.Sample.Views.TreeViewTestView
Step 3. This sample page has a treeview on it, but we need to wrap it with a Flyout, like this:
<Button Content="show flyout"
                Grid.Row="1"
                VerticalAlignment="Top"
                HorizontalAlignment="Left"
                Height="100">
            <Button.Flyout>
                <Flyout>
                    <xc:TreeView x:Name="tvDataBound">
.....................
                    </xc:TreeView>
                </Flyout>
            </Button.Flyout>
        </Button>
Step 4. Run the sample and open this sample page in the app. Click the "show flyout" button.
Step 5. Suppose we have this tree: (bold is the selected node)
  • Branch 1
  • Branch 2
  • Branch 3
Step 6. Click on Branch 2 to expand it:
  • Branch 1
  • Branch 2
    • Branch 2.1
    • Branch 2.2
  • Branch 3
Step 7. Close the popup by tapping outside of it.
Step 8. Click the Show flyout button again. You expect that the selection remains the same and that Branch 2 must be selected, but you can see that Branch 3 (the first expanded branch after the selected one) got selected:
  • Branch 1
  • Branch 2
    • Branch 2.1
    • Branch 2.2
  • Branch 3
Why is it bad?
If I listen to the Selected item changed event, it tells me when popup gets closed that another branch has been selected. If I use the treeview to let the user select a folder to put an item to, the item is being put to completely different folder, which the user didn't select.

This bug occurs only when treeview is in a popup.


Workaround:

We need to prevent OnGotFocus event to occur on TreeViewItem when the popup gets closed.

Open this file:
\WinRTXamlToolkit\WinRTXamlToolkit.Shared\Controls\TreeView\TreeViewItem.cs
Find this method: WinRTXamlToolkit.Controls.TreeViewItem.OnGotFocus(..)

Put this code to the very beginning of the method. Like this:
protected override void OnGotFocus(RoutedEventArgs e)
        {
            var parentPopup = GetParentOfType<Popup>(this.ParentTreeView);
            if (parentPopup != null && !parentPopup.IsOpen)
                return;
And also put this method definition before the method:
        public static T GetParentOfType<T>(FrameworkElement element)
            where T : FrameworkElement
        {
            var ancestor = element;
            while (ancestor != null)
            {
                ancestor = ancestor.Parent as FrameworkElement;
                if (ancestor is T)
                    return (T)ancestor;
            }
            return null;
        }