Browse Source

Remove System.Reactive from Diagnostics package as well

pull/9749/head
Max Katz 4 years ago
parent
commit
bfdd66ac5e
  1. 9
      src/Avalonia.Base/Reactive/Observable.cs
  2. 35
      src/Avalonia.Base/Reactive/SerialDisposableValue.cs
  3. 1
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  4. 17
      src/Avalonia.Diagnostics/Diagnostics/DevTools.cs
  5. 1
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs
  6. 2
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/LogicalTreeNode.cs
  7. 14
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
  8. 18
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs
  9. 54
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs
  10. 1
      src/Avalonia.Diagnostics/Diagnostics/Views/LayoutExplorerView.axaml.cs
  11. 30
      src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs

9
src/Avalonia.Base/Reactive/Observable.cs

@ -44,6 +44,15 @@ internal static class Observable
}, obs.OnError, obs.OnCompleted)); }, obs.OnError, obs.OnCompleted));
}); });
} }
public static IObservable<TSource> StartWith<TSource>(this IObservable<TSource> source, TSource value)
{
return Create<TSource>(obs =>
{
obs.OnNext(value);
return source.Subscribe(obs);
});
}
public static IObservable<TSource> Where<TSource>(this IObservable<TSource> source, Func<TSource, bool> predicate) public static IObservable<TSource> Where<TSource>(this IObservable<TSource> source, Func<TSource, bool> predicate)
{ {

35
src/Avalonia.Base/Reactive/SerialDisposableValue.cs

@ -0,0 +1,35 @@
using System;
using System.Threading;
namespace Avalonia.Reactive;
/// <summary>
/// Represents a disposable resource whose underlying disposable resource can be replaced by another disposable resource, causing automatic disposal of the previous underlying disposable resource.
/// </summary>
internal sealed class SerialDisposableValue : IDisposable
{
private IDisposable? _current;
private bool _disposed;
public IDisposable? Disposable
{
get => _current;
set
{
_current?.Dispose();
_current = value;
if (_disposed)
{
_current?.Dispose();
_current = null;
}
}
}
public void Dispose()
{
_disposed = true;
_current?.Dispose();
}
}

1
src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj

@ -23,7 +23,6 @@
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.8.0" /> <PackageReference Include="Microsoft.CodeAnalysis.Common" Version="3.8.0" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\build\EmbedXaml.props" /> <Import Project="..\..\build\EmbedXaml.props" />
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\BuildTargets.targets" /> <Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\ApiDiff.props" /> <Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" /> <Import Project="..\..\build\NullableEnable.props" />

17
src/Avalonia.Diagnostics/Diagnostics/DevTools.cs

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reactive.Linq;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Diagnostics.Views; using Avalonia.Diagnostics.Views;
using Avalonia.Input; using Avalonia.Input;
@ -72,7 +71,11 @@ namespace Avalonia.Diagnostics
{ {
throw new ArgumentNullException(nameof(application)); throw new ArgumentNullException(nameof(application));
} }
var result = Disposable.Empty;
var openedDisposable = new SerialDisposableValue();
var result = new CompositeDisposable(2);
result.Add(openedDisposable);
// Skip if call on Design Mode // Skip if call on Design Mode
if (!Avalonia.Controls.Design.IsDesignMode if (!Avalonia.Controls.Design.IsDesignMode
&& !s_attachedToApplication) && !s_attachedToApplication)
@ -90,13 +93,15 @@ namespace Avalonia.Diagnostics
{ {
s_attachedToApplication = true; s_attachedToApplication = true;
ObservableExtensions.Subscribe(application.InputManager.PreProcess.OfType<RawKeyEventArgs>(), e => result.Add(application.InputManager.PreProcess.Subscribe(e =>
{ {
if (options.Gesture.Matches(e)) if (e is RawKeyEventArgs keyEventArgs
&& keyEventArgs.Type == RawKeyEventType.KeyUp
&& options.Gesture.Matches(keyEventArgs))
{ {
result = Open(application, options, owner); openedDisposable.Disposable = Open(application, options, owner);
} }
}); }));
} }
} }

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

@ -4,6 +4,7 @@ using Avalonia.Diagnostics.Views;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.ViewModels namespace Avalonia.Diagnostics.ViewModels
{ {

2
src/Avalonia.Diagnostics/Diagnostics/ViewModels/LogicalTreeNode.cs

@ -1,10 +1,10 @@
using System; using System;
using System.Reactive.Disposables;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Lifetimes = Avalonia.Controls.ApplicationLifetimes; using Lifetimes = Avalonia.Controls.ApplicationLifetimes;
using System.Linq; using System.Linq;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.ViewModels namespace Avalonia.Diagnostics.ViewModels
{ {

14
src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs

@ -1,11 +1,11 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Reactive.Linq;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Diagnostics.Models; using Avalonia.Diagnostics.Models;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.ViewModels namespace Avalonia.Diagnostics.ViewModels
{ {
@ -50,15 +50,15 @@ namespace Avalonia.Diagnostics.ViewModels
} }
else else
{ {
#nullable disable _pointerOverSubscription = InputManager.Instance!.PreProcess
_pointerOverSubscription = InputManager.Instance.PreProcess
.OfType<Input.Raw.RawPointerEventArgs>()
.Subscribe(e => .Subscribe(e =>
{ {
PointerOverRoot = e.Root; if (e is Input.Raw.RawPointerEventArgs pointerEventArgs)
PointerOverElement = e.Root.InputHitTest(e.Position); {
PointerOverRoot = pointerEventArgs.Root;
PointerOverElement = pointerEventArgs.Root.InputHitTest(pointerEventArgs.Position);
}
}); });
#nullable restore
} }
Console = new ConsoleViewModel(UpdateConsoleContext); Console = new ConsoleViewModel(UpdateConsoleContext);
} }

18
src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs

@ -1,11 +1,11 @@
using System; using System;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Reactive; using Avalonia.Collections;
using System.Reactive.Linq;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.ViewModels namespace Avalonia.Diagnostics.ViewModels
{ {
@ -28,18 +28,8 @@ namespace Avalonia.Diagnostics.ViewModels
{ {
ElementName = control.Name; ElementName = control.Name;
var removed = Observable.FromEventPattern<LogicalTreeAttachmentEventArgs>( _classesSubscription = ((IObservable<object?>)control.Classes.GetWeakCollectionChangedObservable())
x => control.DetachedFromLogicalTree += x, .StartWith(null)
x => control.DetachedFromLogicalTree -= x);
var classesChanged = Observable.FromEventPattern<
NotifyCollectionChangedEventHandler,
NotifyCollectionChangedEventArgs>(
x => control.Classes.CollectionChanged += x,
x => control.Classes.CollectionChanged -= x)
.TakeUntil(removed);
_classesSubscription = classesChanged.Select(_ => Unit.Default)
.StartWith(Unit.Default)
.Subscribe(_ => .Subscribe(_ =>
{ {
if (control.Classes.Count > 0) if (control.Classes.Count > 0)

54
src/Avalonia.Diagnostics/Diagnostics/ViewModels/VisualTreeNode.cs

@ -1,12 +1,11 @@
using System; using System;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Avalonia.Reactive;
using Lifetimes = Avalonia.Controls.ApplicationLifetimes; using Lifetimes = Avalonia.Controls.ApplicationLifetimes;
using System.Linq; using System.Linq;
@ -61,9 +60,12 @@ namespace Avalonia.Diagnostics.ViewModels
IPopupHostProvider popupHostProvider, IPopupHostProvider popupHostProvider,
string? providerName = null) string? providerName = null)
{ {
return Observable.FromEvent<IPopupHost?>( return Observable.Create<IPopupHost?>(observer =>
x => popupHostProvider.PopupHostChanged += x, {
x => popupHostProvider.PopupHostChanged -= x) void Handler(IPopupHost? args) => observer.OnNext(args);
popupHostProvider.PopupHostChanged += Handler;
return Disposable.Create(() => popupHostProvider.PopupHostChanged -= Handler);
})
.StartWith(popupHostProvider.PopupHost) .StartWith(popupHostProvider.PopupHost)
.Select(popupHost => .Select(popupHost =>
{ {
@ -80,29 +82,39 @@ namespace Avalonia.Diagnostics.ViewModels
{ {
Popup p => GetPopupHostObservable(p), Popup p => GetPopupHostObservable(p),
Control c => Observable.CombineLatest( Control c => Observable.CombineLatest(
c.GetObservable(Control.ContextFlyoutProperty), new IObservable<IPopupHostProvider?>[]
c.GetObservable(Control.ContextMenuProperty), {
c.GetObservable(FlyoutBase.AttachedFlyoutProperty), c.GetObservable(Control.ContextFlyoutProperty),
c.GetObservable(ToolTipDiagnostics.ToolTipProperty), c.GetObservable(Control.ContextMenuProperty),
c.GetObservable(Button.FlyoutProperty), c.GetObservable(FlyoutBase.AttachedFlyoutProperty),
(ContextFlyout, ContextMenu, AttachedFlyout, ToolTip, ButtonFlyout) => c.GetObservable(ToolTipDiagnostics.ToolTipProperty),
c.GetObservable(Button.FlyoutProperty)
})
.Select(
items =>
{ {
if (ContextMenu != null) var contextFlyout = items[0];
var contextMenu = (ContextMenu?)items[1];
var attachedFlyout = items[2];
var toolTip = items[3];
var buttonFlyout = items[4];
if (contextMenu != null)
//Note: ContextMenus are special since all the items are added as visual children. //Note: ContextMenus are special since all the items are added as visual children.
//So we don't need to go via Popup //So we don't need to go via Popup
return Observable.Return<PopupRoot?>(new PopupRoot(ContextMenu)); return Observable.Return<PopupRoot?>(new PopupRoot(contextMenu));
if (ContextFlyout != null) if (contextFlyout != null)
return GetPopupHostObservable(ContextFlyout, "ContextFlyout"); return GetPopupHostObservable(contextFlyout, "ContextFlyout");
if (AttachedFlyout != null) if (attachedFlyout != null)
return GetPopupHostObservable(AttachedFlyout, "AttachedFlyout"); return GetPopupHostObservable(attachedFlyout, "AttachedFlyout");
if (ToolTip != null) if (toolTip != null)
return GetPopupHostObservable(ToolTip, "ToolTip"); return GetPopupHostObservable(toolTip, "ToolTip");
if (ButtonFlyout != null) if (buttonFlyout != null)
return GetPopupHostObservable(ButtonFlyout, "Flyout"); return GetPopupHostObservable(buttonFlyout, "Flyout");
return Observable.Return<PopupRoot?>(null); return Observable.Return<PopupRoot?>(null);
}) })

1
src/Avalonia.Diagnostics/Diagnostics/Views/LayoutExplorerView.axaml.cs

@ -4,6 +4,7 @@ using Avalonia.Controls.Shapes;
using Avalonia.Diagnostics.Controls; using Avalonia.Diagnostics.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.Views namespace Avalonia.Diagnostics.Views
{ {

30
src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Linq;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Diagnostics; using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
@ -13,13 +12,13 @@ using Avalonia.Markup.Xaml;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.Themes.Simple; using Avalonia.Themes.Simple;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Avalonia.Reactive;
namespace Avalonia.Diagnostics.Views namespace Avalonia.Diagnostics.Views
{ {
internal class MainWindow : Window, IStyleHost internal class MainWindow : Window, IStyleHost
{ {
private readonly IDisposable? _keySubscription; private readonly IDisposable? _inputSubscription;
private readonly IDisposable? _pointerSubscription;
private readonly Dictionary<Popup, IDisposable> _frozenPopupStates; private readonly Dictionary<Popup, IDisposable> _frozenPopupStates;
private AvaloniaObject? _root; private AvaloniaObject? _root;
private PixelPoint _lastPointerPosition; private PixelPoint _lastPointerPosition;
@ -33,15 +32,19 @@ namespace Avalonia.Diagnostics.Views
if (Theme is null && this.FindResource(typeof(Window)) is ControlTheme windowTheme) if (Theme is null && this.FindResource(typeof(Window)) is ControlTheme windowTheme)
Theme = windowTheme; Theme = windowTheme;
_keySubscription = InputManager.Instance?.Process _inputSubscription = InputManager.Instance?.Process
.OfType<RawKeyEventArgs>() .Subscribe(x =>
.Where(x => x.Type == RawKeyEventType.KeyDown) {
.Subscribe(RawKeyDown); if (x is RawPointerEventArgs pointerEventArgs)
_pointerSubscription = InputManager.Instance?.Process {
.OfType<RawPointerEventArgs>() _lastPointerPosition = ((Visual)x.Root).PointToScreen(pointerEventArgs.Position);
.Subscribe(x => _lastPointerPosition = ((Visual)x.Root).PointToScreen(x.Position)); }
else if (x is RawKeyEventArgs keyEventArgs && keyEventArgs.Type == RawKeyEventType.KeyDown)
{
RawKeyDown(keyEventArgs);
}
});
_frozenPopupStates = new Dictionary<Popup, IDisposable>(); _frozenPopupStates = new Dictionary<Popup, IDisposable>();
EventHandler? lh = default; EventHandler? lh = default;
@ -94,8 +97,7 @@ namespace Avalonia.Diagnostics.Views
protected override void OnClosed(EventArgs e) protected override void OnClosed(EventArgs e)
{ {
base.OnClosed(e); base.OnClosed(e);
_keySubscription?.Dispose(); _inputSubscription?.Dispose();
_pointerSubscription?.Dispose();
foreach (var state in _frozenPopupStates) foreach (var state in _frozenPopupStates)
{ {

Loading…
Cancel
Save