Browse Source

Apply requested changes and some more clean up.

pull/1888/head
Siegfried Pammer 8 years ago
parent
commit
032fc349f9
  1. 32
      src/Avalonia.Diagnostics/Models/EventChainLink.cs
  2. 97
      src/Avalonia.Diagnostics/ViewModels/EventEntryTreeNode.cs
  3. 18
      src/Avalonia.Diagnostics/ViewModels/EventOwnerTreeNode.cs
  4. 118
      src/Avalonia.Diagnostics/ViewModels/EventTreeNode.cs
  5. 78
      src/Avalonia.Diagnostics/ViewModels/EventTreeNodeBase.cs
  6. 33
      src/Avalonia.Diagnostics/ViewModels/EventsViewModel.cs
  7. 31
      src/Avalonia.Diagnostics/ViewModels/FiredEvent.cs
  8. 4
      src/Avalonia.Diagnostics/Views/EventsView.xaml
  9. 8
      src/Avalonia.Diagnostics/Views/EventsView.xaml.cs

32
src/Avalonia.Diagnostics/Models/ChainLink.cs → src/Avalonia.Diagnostics/Models/EventChainLink.cs

@ -1,13 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
// 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 Avalonia.Interactivity;
namespace Avalonia.Diagnostics.Models
{
internal class ChainLink
internal class EventChainLink
{
public object Handler { get; private set; }
public EventChainLink(object handler, bool handled, RoutingStrategies route)
{
Contract.Requires<ArgumentNullException>(handler != null);
this.Handler = handler;
this.Handled = handled;
this.Route = route;
}
public object Handler { get; }
public string HandlerName
{
get
@ -19,16 +30,9 @@ namespace Avalonia.Diagnostics.Models
return Handler.GetType().Name;
}
}
public bool Handled { get; private set; }
public RoutingStrategies Route { get; private set; }
public ChainLink(object handler, bool handled, RoutingStrategies route)
{
Contract.Requires<ArgumentNullException>(handler != null);
public bool Handled { get; }
this.Handler = handler;
this.Handled = handled;
this.Route = route;
}
public RoutingStrategies Route { get; }
}
}

97
src/Avalonia.Diagnostics/ViewModels/EventEntryTreeNode.cs

@ -1,97 +0,0 @@
// 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 Avalonia.Diagnostics.Models;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels
{
internal class EventEntryTreeNode : EventTreeNode
{
RoutedEvent _event;
EventsViewModel _parentViewModel;
bool _isRegistered;
FiredEvent _currentEvent;
public EventEntryTreeNode(ControlTreeNode parent, RoutedEvent @event, EventsViewModel vm)
: base(parent, @event.Name)
{
Contract.Requires<ArgumentNullException>(@event != null);
Contract.Requires<ArgumentNullException>(vm != null);
this._event = @event;
this._parentViewModel = vm;
}
public override bool? IsEnabled
{
get => base.IsEnabled;
set
{
if (base.IsEnabled != value)
{
base.IsEnabled = value;
UpdateTracker();
if (Parent != null && _updateParent)
{
try
{
Parent._updateChildren = false;
Parent.UpdateChecked();
}
finally
{
Parent._updateChildren = true;
}
}
}
}
}
private void UpdateTracker()
{
if (IsEnabled.GetValueOrDefault() && !_isRegistered)
{
_event.AddClassHandler(typeof(object), HandleEvent, (RoutingStrategies)7, handledEventsToo: true);
_isRegistered = true;
}
}
private void HandleEvent(object sender, RoutedEventArgs e)
{
if (!_isRegistered || IsEnabled == false)
return;
if (sender is IVisual v && DevTools.BelongsToDevTool(v))
return;
var s = sender;
var handled = e.Handled;
var route = e.Route;
Action handler = delegate
{
if (_currentEvent == null || !_currentEvent.IsPartOfSameEventChain(e))
{
_currentEvent = new FiredEvent(e, new ChainLink(s, handled, route));
_parentViewModel.RecordedEvents.Add(_currentEvent);
while (_parentViewModel.RecordedEvents.Count > 100)
_parentViewModel.RecordedEvents.RemoveAt(0);
}
else
{
_currentEvent.AddToChain(new ChainLink(s, handled, route));
}
};
if (!Dispatcher.UIThread.CheckAccess())
Dispatcher.UIThread.Post(handler);
else
handler();
}
}
}

18
src/Avalonia.Diagnostics/ViewModels/ControlTreeNode.cs → src/Avalonia.Diagnostics/ViewModels/EventOwnerTreeNode.cs

@ -11,16 +11,9 @@ using Avalonia.Interactivity;
namespace Avalonia.Diagnostics.ViewModels
{
internal class ControlTreeNode : EventTreeNode
internal class EventOwnerTreeNode : EventTreeNodeBase
{
public ControlTreeNode(Type type, IEnumerable<RoutedEvent> events, EventsViewModel vm)
: base(null, type.Name)
{
this.Children = new AvaloniaList<EventTreeNode>(events.OrderBy(e => e.Name).Select(e => new EventEntryTreeNode(this, e, vm) { IsEnabled = IsDefault(e) }));
this.IsExpanded = true;
}
RoutedEvent[] defaultEvents = new RoutedEvent[]
private static readonly RoutedEvent[] s_defaultEvents = new RoutedEvent[]
{
Button.ClickEvent,
InputElement.KeyDownEvent,
@ -30,9 +23,12 @@ namespace Avalonia.Diagnostics.ViewModels
InputElement.PointerPressedEvent,
};
private bool IsDefault(RoutedEvent e)
public EventOwnerTreeNode(Type type, IEnumerable<RoutedEvent> events, EventsViewModel vm)
: base(null, type.Name)
{
return defaultEvents.Contains(e);
this.Children = new AvaloniaList<EventTreeNodeBase>(events.OrderBy(e => e.Name)
.Select(e => new EventTreeNode(this, e, vm) { IsEnabled = s_defaultEvents.Contains(e) }));
this.IsExpanded = true;
}
public override bool? IsEnabled

118
src/Avalonia.Diagnostics/ViewModels/EventTreeNode.cs

@ -1,80 +1,98 @@
// 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.Diagnostics;
using Avalonia.Collections;
using System;
using Avalonia.Diagnostics.Models;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels
{
internal abstract class EventTreeNode : ViewModelBase
internal class EventTreeNode : EventTreeNodeBase
{
internal bool _updateChildren = true;
internal bool _updateParent = true;
private bool _isExpanded;
private bool? _isEnabled = false;
public EventTreeNode(EventTreeNode parent, string text)
{
this.Parent = parent;
this.Text = text;
}
private RoutedEvent _event;
private EventsViewModel _parentViewModel;
private bool _isRegistered;
private FiredEvent _currentEvent;
public IAvaloniaReadOnlyList<EventTreeNode> Children
public EventTreeNode(EventOwnerTreeNode parent, RoutedEvent @event, EventsViewModel vm)
: base(parent, @event.Name)
{
get;
protected set;
}
Contract.Requires<ArgumentNullException>(@event != null);
Contract.Requires<ArgumentNullException>(vm != null);
public bool IsExpanded
{
get { return _isExpanded; }
set { RaiseAndSetIfChanged(ref _isExpanded, value); }
this._event = @event;
this._parentViewModel = vm;
}
public virtual bool? IsEnabled
public override bool? IsEnabled
{
get { return _isEnabled; }
set { RaiseAndSetIfChanged(ref _isEnabled, value); }
get => base.IsEnabled;
set
{
if (base.IsEnabled != value)
{
base.IsEnabled = value;
UpdateTracker();
if (Parent != null && _updateParent)
{
try
{
Parent._updateChildren = false;
Parent.UpdateChecked();
}
finally
{
Parent._updateChildren = true;
}
}
}
}
}
public EventTreeNode Parent
private void UpdateTracker()
{
get;
if (IsEnabled.GetValueOrDefault() && !_isRegistered)
{
_event.AddClassHandler(typeof(object), HandleEvent, (RoutingStrategies)7, handledEventsToo: true);
_isRegistered = true;
}
}
public string Text
private void HandleEvent(object sender, RoutedEventArgs e)
{
get;
private set;
}
if (!_isRegistered || IsEnabled == false)
return;
if (sender is IVisual v && DevTools.BelongsToDevTool(v))
return;
internal void UpdateChecked()
{
IsEnabled = GetValue();
var s = sender;
var handled = e.Handled;
var route = e.Route;
bool? GetValue()
Action handler = delegate
{
if (Children == null)
return false;
bool? value = false;
for (int i = 0; i < Children.Count; i++)
if (_currentEvent == null || !_currentEvent.IsPartOfSameEventChain(e))
{
if (i == 0)
{
value = Children[i].IsEnabled;
continue;
}
_currentEvent = new FiredEvent(e, new EventChainLink(s, handled, route));
if (value != Children[i].IsEnabled)
{
value = null;
break;
}
_parentViewModel.RecordedEvents.Add(_currentEvent);
while (_parentViewModel.RecordedEvents.Count > 100)
_parentViewModel.RecordedEvents.RemoveAt(0);
}
else
{
_currentEvent.AddToChain(new EventChainLink(s, handled, route));
}
};
return value;
}
if (!Dispatcher.UIThread.CheckAccess())
Dispatcher.UIThread.Post(handler);
else
handler();
}
}
}

78
src/Avalonia.Diagnostics/ViewModels/EventTreeNodeBase.cs

@ -0,0 +1,78 @@
// 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.Collections;
namespace Avalonia.Diagnostics.ViewModels
{
internal abstract class EventTreeNodeBase : ViewModelBase
{
internal bool _updateChildren = true;
internal bool _updateParent = true;
private bool _isExpanded;
private bool? _isEnabled = false;
public EventTreeNodeBase(EventTreeNodeBase parent, string text)
{
this.Parent = parent;
this.Text = text;
}
public IAvaloniaReadOnlyList<EventTreeNodeBase> Children
{
get;
protected set;
}
public bool IsExpanded
{
get { return _isExpanded; }
set { RaiseAndSetIfChanged(ref _isExpanded, value); }
}
public virtual bool? IsEnabled
{
get { return _isEnabled; }
set { RaiseAndSetIfChanged(ref _isEnabled, value); }
}
public EventTreeNodeBase Parent
{
get;
}
public string Text
{
get;
private set;
}
internal void UpdateChecked()
{
IsEnabled = GetValue();
bool? GetValue()
{
if (Children == null)
return false;
bool? value = false;
for (int i = 0; i < Children.Count; i++)
{
if (i == 0)
{
value = Children[i].IsEnabled;
continue;
}
if (value != Children[i].IsEnabled)
{
value = null;
break;
}
}
return value;
}
}
}
}

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

@ -2,26 +2,22 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Data.Converters;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
namespace Avalonia.Diagnostics.ViewModels
{
internal class EventsViewModel : ViewModelBase
{
private IControl _root;
private readonly IControl _root;
private FiredEvent _selectedEvent;
private ICommand ClearCommand { get; }
public EventsViewModel(IControl root)
{
@ -29,27 +25,11 @@ namespace Avalonia.Diagnostics.ViewModels
this.Nodes = RoutedEventRegistry.Instance.GetAllRegistered()
.GroupBy(e => e.OwnerType)
.OrderBy(e => e.Key.Name)
.Select(g => new ControlTreeNode(g.Key, g, this))
.Select(g => new EventOwnerTreeNode(g.Key, g, this))
.ToArray();
}
private void ClearExecute()
{
Action action = delegate
{
RecordedEvents.Clear();
};
if (!Dispatcher.UIThread.CheckAccess())
{
Dispatcher.UIThread.Post(action);
}
else
{
action();
}
}
public EventTreeNode[] Nodes { get; }
public EventTreeNodeBase[] Nodes { get; }
public ObservableCollection<FiredEvent> RecordedEvents { get; } = new ObservableCollection<FiredEvent>();
@ -58,6 +38,11 @@ namespace Avalonia.Diagnostics.ViewModels
get => _selectedEvent;
set => RaiseAndSetIfChanged(ref _selectedEvent, value);
}
private void Clear()
{
RecordedEvents.Clear();
}
}
internal class BoolToBrushConverter : IValueConverter

31
src/Avalonia.Diagnostics/ViewModels/FiredEvent.cs

@ -3,6 +3,7 @@
using System;
using System.Collections.ObjectModel;
using Avalonia.Diagnostics.Models;
using Avalonia.Interactivity;
@ -11,17 +12,15 @@ namespace Avalonia.Diagnostics.ViewModels
internal class FiredEvent : ViewModelBase
{
private RoutedEventArgs _eventArgs;
private EventChainLink _handledBy;
private ChainLink _handledBy;
private ChainLink _originator;
public FiredEvent(RoutedEventArgs eventArgs, ChainLink originator)
public FiredEvent(RoutedEventArgs eventArgs, EventChainLink originator)
{
Contract.Requires<ArgumentNullException>(eventArgs != null);
Contract.Requires<ArgumentNullException>(originator != null);
this._eventArgs = eventArgs;
this._originator = originator;
this.Originator = originator;
AddToChain(originator);
}
@ -34,7 +33,7 @@ namespace Avalonia.Diagnostics.ViewModels
public bool IsHandled => HandledBy?.Handled == true;
public ObservableCollection<ChainLink> EventChain { get; } = new ObservableCollection<ChainLink>();
public ObservableCollection<EventChainLink> EventChain { get; } = new ObservableCollection<EventChainLink>();
public string DisplayText
{
@ -49,21 +48,9 @@ namespace Avalonia.Diagnostics.ViewModels
}
}
public ChainLink Originator
{
get { return _originator; }
set
{
if (_originator != value)
{
_originator = value;
RaisePropertyChanged();
RaisePropertyChanged(nameof(DisplayText));
}
}
}
public EventChainLink Originator { get; }
public ChainLink HandledBy
public EventChainLink HandledBy
{
get { return _handledBy; }
set
@ -80,10 +67,10 @@ namespace Avalonia.Diagnostics.ViewModels
public void AddToChain(object handler, bool handled, RoutingStrategies route)
{
AddToChain(new ChainLink(handler, handled, route));
AddToChain(new EventChainLink(handler, handled, route));
}
public void AddToChain(ChainLink link)
public void AddToChain(EventChainLink link)
{
EventChain.Add(link);
if (HandledBy == null && link.Handled)

4
src/Avalonia.Diagnostics/Views/EventsView.xaml

@ -7,7 +7,7 @@
<Grid ColumnDefinitions="*,4,3*">
<TreeView Name="tree" Items="{Binding Nodes}" SelectedItem="{Binding SelectedNode, Mode=TwoWay}" Grid.RowSpan="2">
<TreeView.DataTemplates>
<TreeDataTemplate DataType="vm:EventTreeNode"
<TreeDataTemplate DataType="vm:EventTreeNodeBase"
ItemsSource="{Binding Children}">
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</TreeDataTemplate>
@ -46,7 +46,7 @@
</ListBox>
</DockPanel>
<StackPanel Orientation="Horizontal" Grid.Row="3">
<Button Content="Clear" Margin="3" Command="{Binding ClearExecute}" />
<Button Content="Clear" Margin="3" Command="{Binding Clear}" />
</StackPanel>
</Grid>
</Grid>

8
src/Avalonia.Diagnostics/Views/EventsView.xaml.cs

@ -1,4 +1,8 @@
using System.Linq;
// 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.Linq;
using Avalonia.Controls;
using Avalonia.Diagnostics.ViewModels;
using Avalonia.Markup.Xaml;
@ -7,7 +11,7 @@ namespace Avalonia.Diagnostics.Views
{
public class EventsView : UserControl
{
ListBox _events;
private ListBox _events;
public EventsView()
{

Loading…
Cancel
Save