Browse Source

Merge branch 'master' into fix-nested-popups

pull/2928/head
danwalmsley 7 years ago
committed by GitHub
parent
commit
24e67e4770
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      build/Microsoft.Reactive.Testing.props
  2. 2
      build/ReactiveUI.props
  3. 2
      build/Rx.props
  4. 2
      build/System.Memory.props
  5. 3
      dirs.proj
  6. 7
      samples/BindingDemo/ViewModels/MainWindowViewModel.cs
  7. 5
      samples/RenderDemo/ViewModels/MainWindowViewModel.cs
  8. 20
      samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
  9. 204
      src/Avalonia.Controls/WrapPanel.cs
  10. 2
      src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs
  11. 2
      src/Avalonia.ReactiveUI/RoutedViewHost.cs
  12. 2
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  13. 10
      src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
  14. 15
      src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs
  15. 24
      tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
  16. 2
      tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_AttachedProperty.cs
  17. 8
      tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs
  18. 49
      tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs
  19. 4
      tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs
  20. 2
      tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs

2
build/Microsoft.Reactive.Testing.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="Microsoft.Reactive.Testing" Version="4.0.0" />
<PackageReference Include="Microsoft.Reactive.Testing" Version="4.1.6" />
</ItemGroup>
</Project>

2
build/ReactiveUI.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="reactiveui" Version="9.0.1" />
<PackageReference Include="ReactiveUI" Version="10.3.6" />
</ItemGroup>
</Project>

2
build/Rx.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="System.Reactive" Version="4.0.0" />
<PackageReference Include="System.Reactive" Version="4.1.6" />
</ItemGroup>
</Project>

2
build/System.Memory.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.1" />
<PackageReference Include="System.Memory" Version="4.5.3" />
</ItemGroup>
</Project>

3
dirs.proj

@ -8,7 +8,8 @@
<ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/PortableXaml/**/*.*proj" />
<ProjectReference Remove="src/Markup/Avalonia.Markup.Xaml/XamlIl/**/*.*proj" />
</ItemGroup>
<ItemGroup Condition="!Exists('$(MSBuildExtensionsPath)\Xamarin\Android')">
<!--<ItemGroup Condition="!Exists('$(MSBuildExtensionsPath)\Xamarin\Android')">-->
<ItemGroup>
<ProjectReference Remove="src/Android/**/*.*proj" />
<ProjectReference Remove="samples/ControlCatalog.Android/ControlCatalog.Android.csproj" />
</ItemGroup>

7
samples/BindingDemo/ViewModels/MainWindowViewModel.cs

@ -1,10 +1,11 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using ReactiveUI;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Threading;
using ReactiveUI;
namespace BindingDemo.ViewModels
{
@ -56,7 +57,7 @@ namespace BindingDemo.ViewModels
public ObservableCollection<TestItem> Items { get; }
public ObservableCollection<TestItem> SelectedItems { get; }
public ReactiveCommand ShuffleItems { get; }
public ReactiveCommand<Unit, Unit> ShuffleItems { get; }
public string BooleanString
{
@ -89,7 +90,7 @@ namespace BindingDemo.ViewModels
}
public IObservable<string> CurrentTimeObservable { get; }
public ReactiveCommand StringValueCommand { get; }
public ReactiveCommand<object, Unit> StringValueCommand { get; }
public DataAnnotationsErrorViewModel DataAnnotationsValidation { get; } = new DataAnnotationsErrorViewModel();
public ExceptionErrorViewModel ExceptionDataValidation { get; } = new ExceptionErrorViewModel();

5
samples/RenderDemo/ViewModels/MainWindowViewModel.cs

@ -1,4 +1,5 @@
using System;
using System.Reactive;
using ReactiveUI;
namespace RenderDemo.ViewModels
@ -26,7 +27,7 @@ namespace RenderDemo.ViewModels
set { this.RaiseAndSetIfChanged(ref drawFps, value); }
}
public ReactiveCommand ToggleDrawDirtyRects { get; }
public ReactiveCommand ToggleDrawFps { get; }
public ReactiveCommand<Unit, bool> ToggleDrawDirtyRects { get; }
public ReactiveCommand<Unit, bool> ToggleDrawFps { get; }
}
}

20
samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs

@ -4,10 +4,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using ReactiveUI.Legacy;
using ReactiveUI;
using Avalonia.Layout;
@ -18,7 +18,7 @@ namespace VirtualizationDemo.ViewModels
private int _itemCount = 200;
private string _newItemString = "New Item";
private int _newItemIndex;
private IReactiveList<ItemViewModel> _items;
private AvaloniaList<ItemViewModel> _items;
private string _prefix = "Item";
private ScrollBarVisibility _horizontalScrollBarVisibility = ScrollBarVisibility.Auto;
private ScrollBarVisibility _verticalScrollBarVisibility = ScrollBarVisibility.Auto;
@ -54,7 +54,7 @@ namespace VirtualizationDemo.ViewModels
public AvaloniaList<ItemViewModel> SelectedItems { get; }
= new AvaloniaList<ItemViewModel>();
public IReactiveList<ItemViewModel> Items
public AvaloniaList<ItemViewModel> Items
{
get { return _items; }
private set { this.RaiseAndSetIfChanged(ref _items, value); }
@ -93,11 +93,11 @@ namespace VirtualizationDemo.ViewModels
public IEnumerable<ItemVirtualizationMode> VirtualizationModes =>
Enum.GetValues(typeof(ItemVirtualizationMode)).Cast<ItemVirtualizationMode>();
public ReactiveCommand AddItemCommand { get; private set; }
public ReactiveCommand RecreateCommand { get; private set; }
public ReactiveCommand RemoveItemCommand { get; private set; }
public ReactiveCommand SelectFirstCommand { get; private set; }
public ReactiveCommand SelectLastCommand { get; private set; }
public ReactiveCommand<Unit, Unit> AddItemCommand { get; private set; }
public ReactiveCommand<Unit, Unit> RecreateCommand { get; private set; }
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; private set; }
public ReactiveCommand<Unit, Unit> SelectFirstCommand { get; private set; }
public ReactiveCommand<Unit, Unit> SelectLastCommand { get; private set; }
public void RandomizeSize()
{
@ -123,7 +123,7 @@ namespace VirtualizationDemo.ViewModels
{
var items = Enumerable.Range(0, count)
.Select(x => new ItemViewModel(x));
Items = new ReactiveList<ItemViewModel>(items);
Items = new AvaloniaList<ItemViewModel>(items);
}
else if (count > Items.Count)
{
@ -162,7 +162,7 @@ namespace VirtualizationDemo.ViewModels
_prefix = _prefix == "Item" ? "Recreated" : "Item";
var items = Enumerable.Range(0, _itemCount)
.Select(x => new ItemViewModel(x, _prefix));
Items = new ReactiveList<ItemViewModel>(items);
Items = new AvaloniaList<ItemViewModel>(items);
}
private void SelectItem(int index)

204
src/Avalonia.Controls/WrapPanel.cs

@ -15,7 +15,7 @@ namespace Avalonia.Controls
/// Positions child elements in sequential position from left to right,
/// breaking content to the next line at the edge of the containing box.
/// Subsequent ordering happens sequentially from top to bottom or from right to left,
/// depending on the value of the Orientation property.
/// depending on the value of the <see cref="Orientation"/> property.
/// </summary>
public class WrapPanel : Panel, INavigableContainer
{
@ -25,6 +25,18 @@ namespace Avalonia.Controls
public static readonly StyledProperty<Orientation> OrientationProperty =
AvaloniaProperty.Register<WrapPanel, Orientation>(nameof(Orientation), defaultValue: Orientation.Horizontal);
/// <summary>
/// Defines the <see cref="ItemWidth"/> property.
/// </summary>
public static readonly StyledProperty<double> ItemWidthProperty =
AvaloniaProperty.Register<WrapPanel, double>(nameof(ItemWidth), double.NaN);
/// <summary>
/// Defines the <see cref="ItemHeight"/> property.
/// </summary>
public static readonly StyledProperty<double> ItemHeightProperty =
AvaloniaProperty.Register<WrapPanel, double>(nameof(ItemHeight), double.NaN);
/// <summary>
/// Initializes static members of the <see cref="WrapPanel"/> class.
/// </summary>
@ -42,6 +54,24 @@ namespace Avalonia.Controls
set { SetValue(OrientationProperty, value); }
}
/// <summary>
/// Gets or sets the width of all items in the WrapPanel.
/// </summary>
public double ItemWidth
{
get { return GetValue(ItemWidthProperty); }
set { SetValue(ItemWidthProperty, value); }
}
/// <summary>
/// Gets or sets the height of all items in the WrapPanel.
/// </summary>
public double ItemHeight
{
get { return GetValue(ItemHeightProperty); }
set { SetValue(ItemHeightProperty, value); }
}
/// <summary>
/// Gets the next control in the specified direction.
/// </summary>
@ -51,7 +81,9 @@ namespace Avalonia.Controls
/// <returns>The control.</returns>
IInputElement INavigableContainer.GetControl(NavigationDirection direction, IInputElement from, bool wrap)
{
var horiz = Orientation == Orientation.Horizontal;
var orientation = Orientation;
var children = Children;
bool horiz = orientation == Orientation.Horizontal;
int index = Children.IndexOf((IControl)from);
switch (direction)
@ -60,7 +92,7 @@ namespace Avalonia.Controls
index = 0;
break;
case NavigationDirection.Last:
index = Children.Count - 1;
index = children.Count - 1;
break;
case NavigationDirection.Next:
++index;
@ -82,9 +114,9 @@ namespace Avalonia.Controls
break;
}
if (index >= 0 && index < Children.Count)
if (index >= 0 && index < children.Count)
{
return Children[index];
return children[index];
}
else
{
@ -95,116 +127,140 @@ namespace Avalonia.Controls
/// <inheritdoc/>
protected override Size MeasureOverride(Size constraint)
{
var curLineSize = new UVSize(Orientation);
var panelSize = new UVSize(Orientation);
var uvConstraint = new UVSize(Orientation, constraint.Width, constraint.Height);
var childConstraint = new Size(constraint.Width, constraint.Height);
for (int i = 0, count = Children.Count; i < count; i++)
double itemWidth = ItemWidth;
double itemHeight = ItemHeight;
var orientation = Orientation;
var children = Children;
var curLineSize = new UVSize(orientation);
var panelSize = new UVSize(orientation);
var uvConstraint = new UVSize(orientation, constraint.Width, constraint.Height);
bool itemWidthSet = !double.IsNaN(itemWidth);
bool itemHeightSet = !double.IsNaN(itemHeight);
var childConstraint = new Size(
itemWidthSet ? itemWidth : constraint.Width,
itemHeightSet ? itemHeight : constraint.Height);
for (int i = 0, count = children.Count; i < count; i++)
{
var child = Children[i];
if (child == null) continue;
//Flow passes its own constrint to children
child.Measure(childConstraint);
//this is the size of the child in UV space
var sz = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) //need to switch to another line
var child = children[i];
if (child != null)
{
panelSize.U = Max(curLineSize.U, panelSize.U);
panelSize.V += curLineSize.V;
curLineSize = sz;
// Flow passes its own constraint to children
child.Measure(childConstraint);
// This is the size of the child in UV space
var sz = new UVSize(orientation,
itemWidthSet ? itemWidth : child.DesiredSize.Width,
itemHeightSet ? itemHeight : child.DesiredSize.Height);
if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) //the element is wider then the constrint - give it a separate line
if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) // Need to switch to another line
{
panelSize.U = Max(sz.U, panelSize.U);
panelSize.V += sz.V;
curLineSize = new UVSize(Orientation);
panelSize.U = Max(curLineSize.U, panelSize.U);
panelSize.V += curLineSize.V;
curLineSize = sz;
if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) // The element is wider then the constraint - give it a separate line
{
panelSize.U = Max(sz.U, panelSize.U);
panelSize.V += sz.V;
curLineSize = new UVSize(orientation);
}
}
else // Continue to accumulate a line
{
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
}
}
else //continue to accumulate a line
{
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
}
}
//the last line size, if any should be added
// The last line size, if any should be added
panelSize.U = Max(curLineSize.U, panelSize.U);
panelSize.V += curLineSize.V;
//go from UV space to W/H space
// Go from UV space to W/H space
return new Size(panelSize.Width, panelSize.Height);
}
/// <inheritdoc/>
protected override Size ArrangeOverride(Size finalSize)
{
double itemWidth = ItemWidth;
double itemHeight = ItemHeight;
var orientation = Orientation;
var children = Children;
int firstInLine = 0;
double accumulatedV = 0;
UVSize curLineSize = new UVSize(Orientation);
UVSize uvFinalSize = new UVSize(Orientation, finalSize.Width, finalSize.Height);
for (int i = 0; i < Children.Count; i++)
double itemU = orientation == Orientation.Horizontal ? itemWidth : itemHeight;
var curLineSize = new UVSize(orientation);
var uvFinalSize = new UVSize(orientation, finalSize.Width, finalSize.Height);
bool itemWidthSet = !double.IsNaN(itemWidth);
bool itemHeightSet = !double.IsNaN(itemHeight);
bool useItemU = orientation == Orientation.Horizontal ? itemWidthSet : itemHeightSet;
for (int i = 0; i < children.Count; i++)
{
var child = Children[i];
if (child == null) continue;
var child = children[i];
if (child != null)
{
var sz = new UVSize(orientation,
itemWidthSet ? itemWidth : child.DesiredSize.Width,
itemHeightSet ? itemHeight : child.DesiredSize.Height);
var sz = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) // Need to switch to another line
{
ArrangeLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU);
if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) //need to switch to another line
{
arrangeLine(accumulatedV, curLineSize.V, firstInLine, i);
accumulatedV += curLineSize.V;
curLineSize = sz;
accumulatedV += curLineSize.V;
curLineSize = sz;
if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) // The element is wider then the constraint - give it a separate line
{
// Switch to next line which only contain one element
ArrangeLine(accumulatedV, sz.V, i, ++i, useItemU, itemU);
if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) //the element is wider then the constraint - give it a separate line
accumulatedV += sz.V;
curLineSize = new UVSize(orientation);
}
firstInLine = i;
}
else // Continue to accumulate a line
{
//switch to next line which only contain one element
arrangeLine(accumulatedV, sz.V, i, ++i);
accumulatedV += sz.V;
curLineSize = new UVSize(Orientation);
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
}
firstInLine = i;
}
else //continue to accumulate a line
{
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
}
}
//arrange the last line, if any
if (firstInLine < Children.Count)
// Arrange the last line, if any
if (firstInLine < children.Count)
{
arrangeLine(accumulatedV, curLineSize.V, firstInLine, Children.Count);
ArrangeLine(accumulatedV, curLineSize.V, firstInLine, children.Count, useItemU, itemU);
}
return finalSize;
}
private void arrangeLine(double v, double lineV, int start, int end)
private void ArrangeLine(double v, double lineV, int start, int end, bool useItemU, double itemU)
{
var orientation = Orientation;
var children = Children;
double u = 0;
bool isHorizontal = (Orientation == Orientation.Horizontal);
bool isHorizontal = orientation == Orientation.Horizontal;
for (int i = start; i < end; i++)
{
var child = Children[i];
var child = children[i];
if (child != null)
{
UVSize childSize = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
double layoutSlotU = childSize.U;
var childSize = new UVSize(orientation, child.DesiredSize.Width, child.DesiredSize.Height);
double layoutSlotU = useItemU ? itemU : childSize.U;
child.Arrange(new Rect(
(isHorizontal ? u : v),
(isHorizontal ? v : u),
(isHorizontal ? layoutSlotU : lineV),
(isHorizontal ? lineV : layoutSlotU)));
isHorizontal ? u : v,
isHorizontal ? v : u,
isHorizontal ? layoutSlotU : lineV,
isHorizontal ? lineV : layoutSlotU));
u += layoutSlotU;
}
}
@ -232,12 +288,12 @@ namespace Avalonia.Controls
internal double Width
{
get { return (_orientation == Orientation.Horizontal ? U : V); }
get { return _orientation == Orientation.Horizontal ? U : V; }
set { if (_orientation == Orientation.Horizontal) U = value; else V = value; }
}
internal double Height
{
get { return (_orientation == Orientation.Horizontal ? V : U); }
get { return _orientation == Orientation.Horizontal ? V : U; }
set { if (_orientation == Orientation.Horizontal) V = value; else U = value; }
}
}

2
src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs

@ -27,7 +27,7 @@ namespace Avalonia.ReactiveUI
/// <summary>
/// Returns activation observable for activatable Avalonia view.
/// </summary>
public IObservable<bool> GetActivationForView(IActivatable view)
public IObservable<bool> GetActivationForView(IActivatableView view)
{
if (!(view is IVisual visual)) return Observable.Return(false);
if (view is WindowBase window) return GetActivationForWindowBase(window);

2
src/Avalonia.ReactiveUI/RoutedViewHost.cs

@ -53,7 +53,7 @@ namespace Avalonia.ReactiveUI
/// ReactiveUI routing documentation website</see> for more info.
/// </para>
/// </remarks>
public class RoutedViewHost : TransitioningContentControl, IActivatable, IEnableLogger
public class RoutedViewHost : TransitioningContentControl, IActivatableView, IEnableLogger
{
/// <summary>
/// <see cref="AvaloniaProperty"/> for the <see cref="Router"/> property.

2
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -540,7 +540,7 @@ namespace Avalonia.Rendering
foreach (var visual in _recalculateChildren)
{
var node = scene.FindNode(visual);
((VisualNode)node)?.UpdateChildren(scene);
((VisualNode)node)?.SortChildren(scene);
}
_recalculateChildren.Clear();

10
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@ -53,6 +53,16 @@ namespace Avalonia.Rendering.SceneGraph
if (visual.VisualRoot != null)
{
if (node?.Parent != null &&
visual.VisualParent != null &&
node.Parent.Visual != visual.VisualParent)
{
// The control has changed parents. Remove the node and recurse into the new parent node.
((VisualNode)node.Parent).RemoveChild(node);
Deindex(scene, node);
node = (VisualNode)scene.FindNode(visual.VisualParent);
}
if (visual.IsVisible)
{
// If the node isn't yet part of the scene, find the nearest ancestor that is.

15
src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs

@ -174,12 +174,12 @@ namespace Avalonia.Rendering.SceneGraph
/// <summary>
/// Sorts the <see cref="Children"/> collection according to the order of the visual's
/// children and their z-index and removes controls that are no longer children.
/// children and their z-index.
/// </summary>
/// <param name="scene">The scene that the node is a part of.</param>
public void UpdateChildren(Scene scene)
public void SortChildren(Scene scene)
{
if (_children == null || _children.Count == 0)
if (_children == null || _children.Count <= 1)
{
return;
}
@ -193,12 +193,9 @@ namespace Avalonia.Rendering.SceneGraph
keys.Add(((long)zIndex << 32) + i);
}
var toRemove = _children.ToList();
keys.Sort();
_children.Clear();
foreach (var i in keys)
{
var child = Visual.VisualChildren[(int)(i & 0xffffffff)];
@ -207,14 +204,8 @@ namespace Avalonia.Rendering.SceneGraph
if (node != null)
{
_children.Add(node);
toRemove.Remove(node);
}
}
foreach (var node in toRemove)
{
scene.Remove(node);
}
}
/// <summary>

24
tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs

@ -93,5 +93,29 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new Rect(0, 0, 100, 50), target.Children[0].Bounds);
Assert.Equal(new Rect(100, 0, 100, 50), target.Children[1].Bounds);
}
[Fact]
public void Applies_ItemWidth_And_ItemHeight_Properties()
{
var target = new WrapPanel()
{
Orientation = Orientation.Horizontal,
Width = 50,
ItemWidth = 20,
ItemHeight = 15,
Children =
{
new Border(),
new Border(),
}
};
target.Measure(Size.Infinity);
target.Arrange(new Rect(target.DesiredSize));
Assert.Equal(new Size(50, 15), target.Bounds.Size);
Assert.Equal(new Rect(0, 0, 20, 15), target.Children[0].Bounds);
Assert.Equal(new Rect(20, 0, 20, 15), target.Children[1].Bounds);
}
}
}

2
tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_AttachedProperty.cs

@ -120,6 +120,8 @@ namespace Avalonia.Markup.UnitTests.Parsers
var result = run();
result.Item1.Subscribe(x => { });
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Assert.Null(result.Item2.Target);

8
tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs

@ -20,9 +20,9 @@ namespace Avalonia.ReactiveUI.UnitTests
{
public class AvaloniaActivationForViewFetcherTest
{
public class TestUserControl : UserControl, IActivatable { }
public class TestUserControl : UserControl, IActivatableView { }
public class TestUserControlWithWhenActivated : UserControl, IActivatable
public class TestUserControlWithWhenActivated : UserControl, IActivatableView
{
public bool Active { get; private set; }
@ -38,7 +38,7 @@ namespace Avalonia.ReactiveUI.UnitTests
}
}
public class TestWindowWithWhenActivated : Window, IActivatable
public class TestWindowWithWhenActivated : Window, IActivatableView
{
public bool Active { get; private set; }
@ -54,7 +54,7 @@ namespace Avalonia.ReactiveUI.UnitTests
}
}
public class ActivatableViewModel : ISupportsActivation
public class ActivatableViewModel : IActivatableViewModel
{
public ViewModelActivator Activator { get; }

49
tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs

@ -96,6 +96,55 @@ namespace Avalonia.Visuals.UnitTests.Rendering
Assert.Equal(new List<IVisual> { root, decorator, border, canvas }, result);
}
[Fact]
public void Should_Add_Dirty_Rect_On_Child_Remove()
{
var dispatcher = new ImmediateDispatcher();
var loop = new Mock<IRenderLoop>();
Decorator decorator;
Border border;
var root = new TestRoot
{
Width = 100,
Height= 100,
Child = decorator = new Decorator
{
Child = border = new Border
{
Width = 50,
Height = 50,
Background = Brushes.Red,
},
}
};
root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize));
var sceneBuilder = new SceneBuilder();
var target = new DeferredRenderer(
root,
loop.Object,
sceneBuilder: sceneBuilder,
dispatcher: dispatcher);
root.Renderer = target;
target.Start();
RunFrame(target);
decorator.Child = null;
RunFrame(target);
var scene = target.UnitTestScene();
var stackNode = scene.FindNode(decorator);
var dirty = scene.Layers[0].Dirty.ToList();
Assert.Equal(1, dirty.Count);
Assert.Equal(new Rect(25, 25, 50, 50), dirty[0]);
}
[Fact]
public void Should_Update_VisualNode_Order_On_Child_Remove_Insert()
{

4
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs

@ -521,8 +521,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
moveFromNode = (VisualNode)scene.FindNode(moveFrom);
moveToNode = (VisualNode)scene.FindNode(moveTo);
moveFromNode.UpdateChildren(scene);
moveToNode.UpdateChildren(scene);
moveFromNode.SortChildren(scene);
moveToNode.SortChildren(scene);
sceneBuilder.Update(scene, moveFrom);
sceneBuilder.Update(scene, moveTo);
sceneBuilder.Update(scene, moveMe);

2
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/VisualNodeTests.cs

@ -99,7 +99,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var node = new VisualNode(Mock.Of<IVisual>(), null);
var scene = new Scene(Mock.Of<IVisual>());
node.UpdateChildren(scene);
node.SortChildren(scene);
}
}
}

Loading…
Cancel
Save