Browse Source

Merge pull request #712 from AvaloniaUI/fixes/706-dropdown-memory-leak

Memory leak fixes
pull/717/head
danwalmsley 10 years ago
committed by GitHub
parent
commit
74bcc67850
  1. 29
      src/Avalonia.Controls/Primitives/Popup.cs
  2. 8
      src/Avalonia.Themes.Default/DropDown.xaml
  3. 63
      tests/Avalonia.Controls.UnitTests/DropDownTests.cs
  4. 18
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

29
src/Avalonia.Controls/Primitives/Popup.cs

@ -68,6 +68,7 @@ namespace Avalonia.Controls.Primitives
private PopupRoot _popupRoot;
private TopLevel _topLevel;
private IDisposable _nonClientListener;
bool _ignoreIsOpenChanged = false;
/// <summary>
/// Initializes static members of the <see cref="Popup"/> class.
@ -220,7 +221,11 @@ namespace Avalonia.Controls.Primitives
PopupRootCreated?.Invoke(this, EventArgs.Empty);
_popupRoot.Show();
_ignoreIsOpenChanged = true;
IsOpen = true;
_ignoreIsOpenChanged = false;
Opened?.Invoke(this, EventArgs.Empty);
}
@ -268,8 +273,13 @@ namespace Avalonia.Controls.Primitives
{
base.OnDetachedFromLogicalTree(e);
_topLevel = null;
_popupRoot?.Dispose();
_popupRoot = null;
if (_popupRoot != null)
{
((ISetLogicalParent)_popupRoot).SetParent(null);
_popupRoot.Dispose();
_popupRoot = null;
}
}
/// <summary>
@ -278,13 +288,16 @@ namespace Avalonia.Controls.Primitives
/// <param name="e">The event args.</param>
private void IsOpenChanged(AvaloniaPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
Open();
}
else
if (!_ignoreIsOpenChanged)
{
Close();
if ((bool)e.NewValue)
{
Open();
}
else
{
Close();
}
}
}

8
src/Avalonia.Themes.Default/DropDown.xaml

@ -10,10 +10,10 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid ColumnDefinitions="*,Auto">
<ContentPresenter Content="{TemplateBinding SelectionBoxItem}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
<ContentControl Content="{TemplateBinding SelectionBoxItem}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
<ToggleButton Name="toggle"
BorderThickness="0"
Background="Transparent"

63
tests/Avalonia.Controls.UnitTests/DropDownTests.cs

@ -1,20 +1,65 @@
// 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.Linq;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Platform;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoMoq;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Xunit;
namespace Avalonia.Controls.UnitTests
{
public class DropDownTests
{
[Fact]
public void SelectionBoxItem_Is_Rectangle_With_VisualBrush_When_Selection_Is_Control()
{
var items = new[] { new Canvas() };
var target = new DropDown
{
Items = items,
SelectedIndex = 0,
};
var rectangle = target.GetValue(DropDown.SelectionBoxItemProperty) as Rectangle;
Assert.NotNull(rectangle);
var brush = rectangle.Fill as VisualBrush;
Assert.NotNull(brush);
Assert.Same(items[0], brush.Visual);
}
[Fact]
public void SelectionBoxItem_Rectangle_Is_Removed_From_Logical_Tree()
{
var target = new DropDown
{
Items = new[] { new Canvas() },
SelectedIndex = 0,
Template = GetTemplate(),
};
var root = new TestRoot { Child = target };
target.ApplyTemplate();
target.Presenter.ApplyTemplate();
var rectangle = target.GetValue(DropDown.SelectionBoxItemProperty) as Rectangle;
Assert.True(((ILogical)target).IsAttachedToLogicalTree);
Assert.True(((ILogical)rectangle).IsAttachedToLogicalTree);
rectangle.DetachedFromLogicalTree += (s, e) => { };
root.Child = null;
Assert.False(((ILogical)target).IsAttachedToLogicalTree);
Assert.False(((ILogical)rectangle).IsAttachedToLogicalTree);
}
private FuncControlTemplate GetTemplate()
{
return new FuncControlTemplate<DropDown>(parent =>
@ -26,8 +71,7 @@ namespace Avalonia.Controls.UnitTests
{
new ContentControl
{
Name = "contentControl",
[~ContentPresenter.ContentProperty] = parent[~DropDown.SelectionBoxItemProperty],
[!ContentControl.ContentProperty] = parent[!DropDown.SelectionBoxItemProperty],
},
new ToggleButton
{
@ -35,7 +79,12 @@ namespace Avalonia.Controls.UnitTests
},
new Popup
{
Name = "popup",
Name = "PART_Popup",
Child = new ItemsPresenter
{
Name = "PART_ItemsPresenter",
[!ItemsPresenter.ItemsProperty] = parent[!DropDown.ItemsProperty],
}
}
}
};

18
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@ -166,6 +166,24 @@ namespace Avalonia.Controls.UnitTests.Primitives
}
}
[Fact]
public void PopupRoot_Should_Be_Detached_From_Logical_Tree_When_Popup_Is_Detached()
{
using (CreateServices())
{
var target = new Popup();
var root = new TestRoot { Child = target };
target.Open();
var popupRoot = (ILogical)target.PopupRoot;
Assert.True(popupRoot.IsAttachedToLogicalTree);
root.Child = null;
Assert.False(((ILogical)target).IsAttachedToLogicalTree);
}
}
[Fact]
public void PopupRoot_Should_Have_Template_Applied()
{

Loading…
Cancel
Save