Browse Source

Merge branch 'master' into fixes/2660-treeview-selection

pull/2702/head
Steven Kirk 7 years ago
committed by GitHub
parent
commit
4eab39fa8a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      src/Avalonia.Diagnostics/DevTools.xaml
  2. 8
      src/Avalonia.Diagnostics/DevTools.xaml.cs
  3. 2
      src/Avalonia.Diagnostics/ViewLocator.cs
  4. 65
      src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs
  5. 13
      src/Avalonia.Diagnostics/ViewModels/EventsViewModel.cs
  6. 16
      src/Avalonia.Diagnostics/ViewModels/IDevToolViewModel.cs
  7. 7
      src/Avalonia.Diagnostics/ViewModels/TreePageViewModel.cs
  8. 16
      src/Avalonia.Diagnostics/Views/ControlDetailsView.cs
  9. 5
      src/Avalonia.Diagnostics/Views/PropertyChangedExtensions.cs
  10. 3
      src/Avalonia.Diagnostics/Views/TreePage.xaml.cs

37
src/Avalonia.Diagnostics/DevTools.xaml

@ -1,23 +1,24 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Avalonia.Diagnostics.DevTools"> x:Class="Avalonia.Diagnostics.DevTools">
<Grid RowDefinitions="Auto,*,Auto"> <Grid RowDefinitions="*,Auto" Margin="4">
<TabStrip SelectedIndex="{Binding SelectedTab, Mode=TwoWay}">
<TabStripItem Content="Logical Tree"/>
<TabStripItem Content="Visual Tree"/>
<TabStripItem Content="Events"/>
</TabStrip>
<ContentControl Content="{Binding Content}" Grid.Row="1"/> <TabControl Grid.Row="0" Items="{Binding Tools}" SelectedItem="{Binding SelectedTool}">
<TabControl.ItemTemplate>
<StackPanel Spacing="4" Orientation="Horizontal" Grid.Row="2"> <DataTemplate>
<TextBlock>Hold Ctrl+Shift over a control to inspect.</TextBlock> <TextBlock Text="{Binding Name}" />
<Separator Width="8"/> </DataTemplate>
<TextBlock>Focused:</TextBlock> </TabControl.ItemTemplate>
<TextBlock Text="{Binding FocusedControl}"/> </TabControl>
<Separator Width="8"/>
<TextBlock>Pointer Over:</TextBlock> <StackPanel Grid.Row="1" Spacing="4" Orientation="Horizontal">
<TextBlock Text="{Binding PointerOverElement}"/> <TextBlock>Hold Ctrl+Shift over a control to inspect.</TextBlock>
</StackPanel> <Separator Width="8" />
</Grid> <TextBlock>Focused:</TextBlock>
<TextBlock Text="{Binding FocusedControl}" />
<Separator Width="8" />
<TextBlock>Pointer Over:</TextBlock>
<TextBlock Text="{Binding PointerOverElement}" />
</StackPanel>
</Grid>
</UserControl> </UserControl>

8
src/Avalonia.Diagnostics/DevTools.xaml.cs

@ -1,10 +1,13 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Diagnostics.ViewModels; using Avalonia.Diagnostics.ViewModels;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
@ -82,7 +85,8 @@ namespace Avalonia.Diagnostics
DataTemplates = DataTemplates =
{ {
new ViewLocator<ViewModelBase>(), new ViewLocator<ViewModelBase>(),
} },
Title = "Avalonia DevTools"
}; };
devToolsWindow.Closed += devTools.DevToolsClosed; devToolsWindow.Closed += devTools.DevToolsClosed;

2
src/Avalonia.Diagnostics/ViewLocator.cs

@ -31,4 +31,4 @@ namespace Avalonia.Diagnostics
return data is TViewModel; return data is TViewModel;
} }
} }
} }

65
src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs

@ -2,7 +2,9 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Reactive.Linq; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
@ -10,21 +12,23 @@ namespace Avalonia.Diagnostics.ViewModels
{ {
internal class DevToolsViewModel : ViewModelBase internal class DevToolsViewModel : ViewModelBase
{ {
private ViewModelBase _content; private IDevToolViewModel _selectedTool;
private int _selectedTab;
private TreePageViewModel _logicalTree;
private TreePageViewModel _visualTree;
private EventsViewModel _eventsView;
private string _focusedControl; private string _focusedControl;
private string _pointerOverElement; private string _pointerOverElement;
public DevToolsViewModel(IControl root) public DevToolsViewModel(IControl root)
{ {
_logicalTree = new TreePageViewModel(LogicalTreeNode.Create(root)); Tools = new ObservableCollection<IDevToolViewModel>
_visualTree = new TreePageViewModel(VisualTreeNode.Create(root)); {
_eventsView = new EventsViewModel(root); new TreePageViewModel(LogicalTreeNode.Create(root), "Logical Tree"),
new TreePageViewModel(VisualTreeNode.Create(root), "Visual Tree"),
new EventsViewModel(root)
};
SelectedTool = Tools.First();
UpdateFocusedControl(); UpdateFocusedControl();
KeyboardDevice.Instance.PropertyChanged += (s, e) => KeyboardDevice.Instance.PropertyChanged += (s, e) =>
{ {
if (e.PropertyName == nameof(KeyboardDevice.Instance.FocusedElement)) if (e.PropertyName == nameof(KeyboardDevice.Instance.FocusedElement))
@ -33,58 +37,33 @@ namespace Avalonia.Diagnostics.ViewModels
} }
}; };
SelectedTab = 0;
root.GetObservable(TopLevel.PointerOverElementProperty) root.GetObservable(TopLevel.PointerOverElementProperty)
.Subscribe(x => PointerOverElement = x?.GetType().Name); .Subscribe(x => PointerOverElement = x?.GetType().Name);
} }
public ViewModelBase Content public IDevToolViewModel SelectedTool
{ {
get { return _content; } get => _selectedTool;
private set { RaiseAndSetIfChanged(ref _content, value); } set => RaiseAndSetIfChanged(ref _selectedTool, value);
} }
public int SelectedTab public ObservableCollection<IDevToolViewModel> Tools { get; }
{
get { return _selectedTab; }
set
{
_selectedTab = value;
switch (value)
{
case 0:
Content = _logicalTree;
break;
case 1:
Content = _visualTree;
break;
case 2:
Content = _eventsView;
break;
}
RaisePropertyChanged();
}
}
public string FocusedControl public string FocusedControl
{ {
get { return _focusedControl; } get => _focusedControl;
private set { RaiseAndSetIfChanged(ref _focusedControl, value); } private set => RaiseAndSetIfChanged(ref _focusedControl, value);
} }
public string PointerOverElement public string PointerOverElement
{ {
get { return _pointerOverElement; } get => _pointerOverElement;
private set { RaiseAndSetIfChanged(ref _pointerOverElement, value); } private set => RaiseAndSetIfChanged(ref _pointerOverElement, value);
} }
public void SelectControl(IControl control) public void SelectControl(IControl control)
{ {
var tree = Content as TreePageViewModel; if (SelectedTool is TreePageViewModel tree)
if (tree != null)
{ {
tree.SelectControl(control); tree.SelectControl(control);
} }

13
src/Avalonia.Diagnostics/ViewModels/EventsViewModel.cs

@ -5,8 +5,6 @@ using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Windows.Input;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Data.Converters; using Avalonia.Data.Converters;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@ -14,21 +12,24 @@ using Avalonia.Media;
namespace Avalonia.Diagnostics.ViewModels namespace Avalonia.Diagnostics.ViewModels
{ {
internal class EventsViewModel : ViewModelBase internal class EventsViewModel : ViewModelBase, IDevToolViewModel
{ {
private readonly IControl _root; private readonly IControl _root;
private FiredEvent _selectedEvent; private FiredEvent _selectedEvent;
public EventsViewModel(IControl root) public EventsViewModel(IControl root)
{ {
this._root = root; _root = root;
this.Nodes = RoutedEventRegistry.Instance.GetAllRegistered()
Nodes = RoutedEventRegistry.Instance.GetAllRegistered()
.GroupBy(e => e.OwnerType) .GroupBy(e => e.OwnerType)
.OrderBy(e => e.Key.Name) .OrderBy(e => e.Key.Name)
.Select(g => new EventOwnerTreeNode(g.Key, g, this)) .Select(g => new EventOwnerTreeNode(g.Key, g, this))
.ToArray(); .ToArray();
} }
public string Name => "Events";
public EventTreeNodeBase[] Nodes { get; } public EventTreeNodeBase[] Nodes { get; }
public ObservableCollection<FiredEvent> RecordedEvents { get; } = new ObservableCollection<FiredEvent>(); public ObservableCollection<FiredEvent> RecordedEvents { get; } = new ObservableCollection<FiredEvent>();
@ -49,7 +50,7 @@ namespace Avalonia.Diagnostics.ViewModels
{ {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{ {
return (bool)value ? Brushes.LightGreen : Brushes.Transparent; return (bool)value ? Brushes.Green : Brushes.Transparent;
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

16
src/Avalonia.Diagnostics/ViewModels/IDevToolViewModel.cs

@ -0,0 +1,16 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Diagnostics.ViewModels
{
/// <summary>
/// View model interface for tool showing up in DevTools
/// </summary>
public interface IDevToolViewModel
{
/// <summary>
/// Name of a tool.
/// </summary>
string Name { get; }
}
}

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

@ -6,16 +6,19 @@ using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels namespace Avalonia.Diagnostics.ViewModels
{ {
internal class TreePageViewModel : ViewModelBase internal class TreePageViewModel : ViewModelBase, IDevToolViewModel
{ {
private TreeNode _selected; private TreeNode _selected;
private ControlDetailsViewModel _details; private ControlDetailsViewModel _details;
public TreePageViewModel(TreeNode[] nodes) public TreePageViewModel(TreeNode[] nodes, string name)
{ {
Nodes = nodes; Nodes = nodes;
Name = name;
} }
public string Name { get; }
public TreeNode[] Nodes { get; protected set; } public TreeNode[] Nodes { get; protected set; }
public TreeNode SelectedNode public TreeNode SelectedNode

16
src/Avalonia.Diagnostics/Views/ControlDetailsView.cs

@ -7,7 +7,6 @@ using System.Reactive.Linq;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Diagnostics.ViewModels; using Avalonia.Diagnostics.ViewModels;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Styling;
namespace Avalonia.Diagnostics.Views namespace Avalonia.Diagnostics.Views
{ {
@ -42,16 +41,6 @@ namespace Avalonia.Diagnostics.Views
{ {
Content = _grid = new SimpleGrid Content = _grid = new SimpleGrid
{ {
Styles =
{
new Style(x => x.Is<Control>())
{
Setters = new[]
{
new Setter(MarginProperty, new Thickness(2)),
}
},
},
[GridRepeater.TemplateProperty] = pt, [GridRepeater.TemplateProperty] = pt,
} }
}; };
@ -61,8 +50,11 @@ namespace Avalonia.Diagnostics.Views
{ {
var property = (PropertyDetails)i; var property = (PropertyDetails)i;
var margin = new Thickness(2);
yield return new TextBlock yield return new TextBlock
{ {
Margin = margin,
Text = property.Name, Text = property.Name,
TextWrapping = TextWrapping.NoWrap, TextWrapping = TextWrapping.NoWrap,
[!ToolTip.TipProperty] = property.GetObservable<string>(nameof(property.Diagnostic)).ToBinding(), [!ToolTip.TipProperty] = property.GetObservable<string>(nameof(property.Diagnostic)).ToBinding(),
@ -70,6 +62,7 @@ namespace Avalonia.Diagnostics.Views
yield return new TextBlock yield return new TextBlock
{ {
Margin = margin,
TextWrapping = TextWrapping.NoWrap, TextWrapping = TextWrapping.NoWrap,
[!TextBlock.TextProperty] = property.GetObservable<object>(nameof(property.Value)) [!TextBlock.TextProperty] = property.GetObservable<object>(nameof(property.Value))
.Select(v => v?.ToString()) .Select(v => v?.ToString())
@ -78,6 +71,7 @@ namespace Avalonia.Diagnostics.Views
yield return new TextBlock yield return new TextBlock
{ {
Margin = margin,
TextWrapping = TextWrapping.NoWrap, TextWrapping = TextWrapping.NoWrap,
[!TextBlock.TextProperty] = property.GetObservable<string>((nameof(property.Priority))).ToBinding(), [!TextBlock.TextProperty] = property.GetObservable<string>((nameof(property.Priority))).ToBinding(),
}; };

5
src/Avalonia.Diagnostics/Views/PropertyChangedExtenions.cs → src/Avalonia.Diagnostics/Views/PropertyChangedExtensions.cs

@ -1,4 +1,7 @@
using System; // Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.ComponentModel; using System.ComponentModel;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reflection; using System.Reflection;

3
src/Avalonia.Diagnostics/Views/TreePage.xaml.cs

@ -1,3 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Generators; using Avalonia.Controls.Generators;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;

Loading…
Cancel
Save