A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

173 lines
5.6 KiB

using System;
using System.ComponentModel;
using Avalonia.Controls;
using Avalonia.Diagnostics.Models;
using Avalonia.Input;
using Avalonia.Threading;
namespace Avalonia.Diagnostics.ViewModels
{
internal class MainViewModel : ViewModelBase, IDisposable
{
private readonly TopLevel _root;
private readonly TreePageViewModel _logicalTree;
private readonly TreePageViewModel _visualTree;
private readonly EventsPageViewModel _events;
private readonly IDisposable _pointerOverSubscription;
private ViewModelBase _content;
private int _selectedTab;
private string _focusedControl;
private string _pointerOverElement;
private bool _shouldVisualizeMarginPadding = true;
private bool _shouldVisualizeDirtyRects;
public MainViewModel(TopLevel root)
{
_root = root;
_logicalTree = new TreePageViewModel(this, LogicalTreeNode.Create(root));
_visualTree = new TreePageViewModel(this, VisualTreeNode.Create(root));
_events = new EventsPageViewModel(root);
UpdateFocusedControl();
KeyboardDevice.Instance.PropertyChanged += KeyboardPropertyChanged;
SelectedTab = 0;
_pointerOverSubscription = root.GetObservable(TopLevel.PointerOverElementProperty)
.Subscribe(x => PointerOverElement = x?.GetType().Name);
Console = new ConsoleViewModel(UpdateConsoleContext);
}
public bool ShouldVisualizeMarginPadding
{
get => _shouldVisualizeMarginPadding;
set => RaiseAndSetIfChanged(ref _shouldVisualizeMarginPadding, value);
}
public bool ShouldVisualizeDirtyRects
{
get => _shouldVisualizeDirtyRects;
set
{
RaiseAndSetIfChanged(ref _shouldVisualizeDirtyRects, value);
_root.Renderer.DrawDirtyRects = value;
}
}
public void ToggleVisualizeDirtyRects()
{
ShouldVisualizeDirtyRects = !ShouldVisualizeDirtyRects;
}
public void ToggleVisualizeMarginPadding()
{
ShouldVisualizeMarginPadding = !ShouldVisualizeMarginPadding;
}
public ConsoleViewModel Console { get; }
public ViewModelBase Content
{
get { return _content; }
private set
{
if (_content is TreePageViewModel oldTree &&
value is TreePageViewModel newTree &&
oldTree?.SelectedNode?.Visual is IControl control)
{
// HACK: We want to select the currently selected control in the new tree, but
// to select nested nodes in TreeView, currently the TreeView has to be able to
// expand the parent nodes. Because at this point the TreeView isn't visible,
// this will fail unless we schedule the selection to run after layout.
DispatcherTimer.RunOnce(
() =>
{
try
{
newTree.SelectControl(control);
}
catch { }
},
TimeSpan.FromMilliseconds(0),
DispatcherPriority.ApplicationIdle);
}
RaiseAndSetIfChanged(ref _content, value);
}
}
public int SelectedTab
{
get { return _selectedTab; }
set
{
_selectedTab = value;
switch (value)
{
case 0:
Content = _logicalTree;
break;
case 1:
Content = _visualTree;
break;
case 2:
Content = _events;
break;
}
RaisePropertyChanged();
}
}
public string FocusedControl
{
get { return _focusedControl; }
private set { RaiseAndSetIfChanged(ref _focusedControl, value); }
}
public string PointerOverElement
{
get { return _pointerOverElement; }
private set { RaiseAndSetIfChanged(ref _pointerOverElement, value); }
}
private void UpdateConsoleContext(ConsoleContext context)
{
context.root = _root;
if (Content is TreePageViewModel tree)
{
context.e = tree.SelectedNode?.Visual;
}
}
public void SelectControl(IControl control)
{
var tree = Content as TreePageViewModel;
tree?.SelectControl(control);
}
public void Dispose()
{
KeyboardDevice.Instance.PropertyChanged -= KeyboardPropertyChanged;
_pointerOverSubscription.Dispose();
_logicalTree.Dispose();
_visualTree.Dispose();
_root.Renderer.DrawDirtyRects = false;
}
private void UpdateFocusedControl()
{
FocusedControl = KeyboardDevice.Instance.FocusedElement?.GetType().Name;
}
private void KeyboardPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(KeyboardDevice.Instance.FocusedElement))
{
UpdateFocusedControl();
}
}
}
}