Browse Source

Add context flyout to the dev tools tree

pull/11086/head
Max Katz 3 years ago
parent
commit
8ab2aa7dc9
  1. 107
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs
  2. 14
      src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml
  3. 11
      src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs

107
src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs

@ -1,5 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.LogicalTree;
using Avalonia.Metadata;
using Avalonia.Styling;
using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels
@ -21,6 +27,8 @@ namespace Avalonia.Diagnostics.ViewModels
SettersFilter.RefreshFilter += (s, e) => Details?.UpdateStyleFilters();
}
public event EventHandler<string>? ClipboardCopyRequested;
public MainViewModel MainView { get; }
public FilterViewModel PropertiesFilter { get; }
@ -106,6 +114,105 @@ namespace Avalonia.Diagnostics.ViewModels
}
}
public void CopySelector()
{
var currentVisual = SelectedNode?.Visual as Visual;
if (currentVisual is not null)
{
var selector = GetVisualSelector(currentVisual);
ClipboardCopyRequested?.Invoke(this, selector);
}
}
public void CopySelectorFromTemplateParent()
{
var parts = new List<string>();
var currentVisual = SelectedNode?.Visual as Visual;
while (currentVisual is not null)
{
parts.Add(GetVisualSelector(currentVisual));
currentVisual = currentVisual.TemplatedParent as Visual;
}
if (parts.Any())
{
parts.Reverse();
var selector = string.Join(" /template/ ", parts);
ClipboardCopyRequested?.Invoke(this, selector);
}
}
public void ExpandRecursively()
{
if (SelectedNode is { } selectedNode)
{
ExpandNode(selectedNode);
var stack = new Stack<TreeNode>();
stack.Push(selectedNode);
while (stack.Count > 0)
{
var item = stack.Pop();
item.IsExpanded = true;
foreach (var child in item.Children)
{
stack.Push(child);
}
}
}
}
public void CollapseChildren()
{
if (SelectedNode is { } selectedNode)
{
var stack = new Stack<TreeNode>();
stack.Push(selectedNode);
while (stack.Count > 0)
{
var item = stack.Pop();
item.IsExpanded = false;
foreach (var child in item.Children)
{
stack.Push(child);
}
}
}
}
public void CaptureNodeScreenshot()
{
MainView.Shot(null);
}
public void BringIntoView()
{
(SelectedNode?.Visual as Control)?.BringIntoView();
}
public void Focus()
{
(SelectedNode?.Visual as Control)?.Focus();
}
private static string GetVisualSelector(Visual visual)
{
var name = string.IsNullOrEmpty(visual.Name) ? "" : $"#{visual.Name}";
var classes = string.Concat(visual.Classes
.Where(c => !c.StartsWith(":"))
.Select(c => '.' + c));
var typeName = ((IStyleable)visual).StyleKey.Name;
return $"{typeName}{name}{classes}";
}
private void ExpandNode(TreeNode? node)
{
if (node != null)

14
src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml

@ -26,6 +26,20 @@
<Setter Property="Background" Value="Transparent" />
</Style>
</TreeView.Styles>
<TreeView.ContextFlyout>
<MenuFlyout>
<MenuItem Header="Copy">
<MenuItem Header="Copy individual node selector" Command="{Binding CopySelector}" />
<MenuItem Header="Copy selector from template parent" Command="{Binding CopySelectorFromTemplateParent}" />
</MenuItem>
<MenuItem Header="-" />
<MenuItem Header="Expand recursively" Command="{Binding ExpandRecursively}" />
<MenuItem Header="Collapse children" Command="{Binding CollapseChildren}" />
<MenuItem Header="Capture node screenshot" Command="{Binding CaptureNodeScreenshot}" />
<MenuItem Header="Bring into view" Command="{Binding BringIntoView}" />
<MenuItem Header="Focus" Command="{Binding Focus}" />
</MenuFlyout>
</TreeView.ContextFlyout>
</TreeView>
<GridSplitter Background="{DynamicResource ThemeControlMidBrush}" Width="1" Grid.Column="1"/>

11
src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml.cs

@ -1,3 +1,4 @@
using System;
using System.Diagnostics;
using System.Linq;
using Avalonia.Controls;
@ -38,6 +39,16 @@ namespace Avalonia.Diagnostics.Views
AdornerLayer.SetIsClipEnabled(_adorner, false);
}
protected override void OnDataContextChanged(EventArgs e)
{
base.OnDataContextChanged(e);
((TreePageViewModel)DataContext!).ClipboardCopyRequested += (sender, s) =>
{
TopLevel.GetTopLevel(this)?.Clipboard?.SetTextAsync(s);
};
}
protected void AddAdorner(object? sender, PointerEventArgs e)
{
var node = (TreeNode?)((Control)sender!).DataContext;

Loading…
Cancel
Save