File: ValueTracking\ValueTrackingTree.xaml.cs
Web Access
Project: src\src\VisualStudio\Core\Def\Microsoft.VisualStudio.LanguageServices_pxr0p0dn_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Windows.Controls;
using System.Windows.Input;
 
namespace Microsoft.VisualStudio.LanguageServices.ValueTracking;
 
/// <summary>
/// Interaction logic for ValueTrackingTree.xaml
/// </summary>
internal partial class ValueTrackingTree : UserControl
{
    private readonly ValueTrackingTreeViewModel _viewModel;
 
    public ValueTrackingTree(ValueTrackingTreeViewModel viewModel)
    {
        DataContext = _viewModel = viewModel;
        InitializeComponent();
    }
 
    private void ValueTrackingTree_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        e.Handled = e.Handled || e.Key switch
        {
            Key.Down => TrySelectItem(GetNextItem(expandNode: false), navigate: true),
            Key.Up => TrySelectItem(GetPreviousItem(), navigate: true),
            Key.F8 => e.KeyboardDevice.Modifiers == ModifierKeys.Shift ? TrySelectItem(GetPreviousItem(), navigate: true) : TrySelectItem(GetNextItem(expandNode: true), navigate: true),
            Key.Enter => TrySelectItem(ValueTrackingTreeView.SelectedItem as TreeViewItemBase, navigate: true),
            Key.Right => TrySetExpanded(ValueTrackingTreeView.SelectedItem as TreeViewItemBase, true),
            Key.Left => TrySetExpanded(ValueTrackingTreeView.SelectedItem as TreeViewItemBase, false),
            Key.Space => TryToggleExpanded(ValueTrackingTreeView.SelectedItem as TreeViewItemBase),
            _ => false
        };
 
        // Local Functions
 
        bool TrySelectItem(TreeViewItemBase? node, bool navigate)
        {
            if (node is null)
            {
                return false;
            }
 
            SelectItem(node, navigate);
            return true;
        }
 
        bool TrySetExpanded(TreeViewItemBase? node, bool expanded)
        {
            if (node is null)
            {
                return false;
            }
 
            node.IsNodeExpanded = expanded;
            return true;
        }
 
        bool TryToggleExpanded(TreeViewItemBase? node)
        {
            return TrySetExpanded(node, node is null ? false : !node.IsNodeExpanded);
        }
    }
 
    private void ValueTrackingTree_MouseDoubleClickPreview(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton != MouseButton.Left)
        {
            return;
        }
 
        if (sender is TreeViewItemBase viewModel)
        {
            SelectItem(viewModel, true);
            e.Handled = true;
        }
        else if (sender is TreeView)
        {
            SelectItem(_viewModel.SelectedItem, true);
            e.Handled = true;
        }
    }
 
    private void SelectItem(TreeViewItemBase? item, bool navigate = false)
    {
        _viewModel.SelectedItem = item;
 
        if (navigate && item is TreeItemViewModel navigatableItem)
        {
            navigatableItem.NavigateTo();
        }
    }
 
    private TreeViewItemBase GetNextItem(bool expandNode)
    {
        if (ValueTrackingTreeView.SelectedItem is null)
        {
            return (TreeViewItemBase)ValueTrackingTreeView.Items[0];
        }
 
        var item = (TreeViewItemBase)ValueTrackingTreeView.SelectedItem;
 
        if (expandNode)
        {
            item.IsNodeExpanded = true;
        }
 
        return item.GetNextInTree();
    }
 
    private TreeViewItemBase GetPreviousItem()
    {
        if (ValueTrackingTreeView.SelectedItem is null)
        {
            return (TreeViewItemBase)ValueTrackingTreeView.Items[^1];
        }
 
        var item = (TreeViewItemBase)ValueTrackingTreeView.SelectedItem;
        return item.GetPreviousInTree();
    }
 
    private void ValueTrackingTree_SelectedItemChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<object> e)
    {
        _viewModel.SelectedItem = ValueTrackingTreeView.SelectedItem as TreeViewItemBase;
    }
}