@ -3,7 +3,10 @@ using System.Collections.Generic;
using System.Collections.ObjectModel ;
using System.Linq ;
using System.Reactive.Disposables ;
using Avalonia.Collections ;
using Avalonia.Controls ;
using Avalonia.Controls.Presenters ;
using Avalonia.Controls.Shapes ;
using Avalonia.Controls.Templates ;
using Avalonia.Data ;
@ -67,6 +70,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < DataGrid > ( ) ) . ObjectsCount ) ) ;
}
@ -100,6 +106,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < Canvas > ( ) ) . ObjectsCount ) ) ;
}
@ -141,6 +150,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < Canvas > ( ) ) . ObjectsCount ) ) ;
}
@ -179,6 +191,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < TextBox > ( ) ) . ObjectsCount ) ) ;
dotMemory . Check ( memory = >
@ -216,6 +231,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < TextBox > ( ) ) . ObjectsCount ) ) ;
}
@ -261,6 +279,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < TextBox > ( ) ) . ObjectsCount ) ) ;
dotMemory . Check ( memory = >
@ -351,6 +372,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < TreeView > ( ) ) . ObjectsCount ) ) ;
}
@ -384,6 +408,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < Slider > ( ) ) . ObjectsCount ) ) ;
}
@ -421,6 +448,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < TabItem > ( ) ) . ObjectsCount ) ) ;
}
@ -496,6 +526,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < Canvas > ( ) ) . ObjectsCount ) ) ;
}
@ -536,9 +569,12 @@ namespace Avalonia.LeakTests
initialMenuCount = memory . GetObjects ( where = > where . Type . Is < ContextMenu > ( ) ) . ObjectsCount ;
initialMenuItemCount = memory . GetObjects ( where = > where . Type . Is < MenuItem > ( ) ) . ObjectsCount ;
} ) ;
AttachShowAndDetachContextMenu ( window ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
Mock . Get ( window . PlatformImpl ) . Invocations . Clear ( ) ;
dotMemory . Check ( memory = >
Assert . Equal ( initialMenuCount , memory . GetObjects ( where = > where . Type . Is < ContextMenu > ( ) ) . ObjectsCount ) ) ;
@ -580,10 +616,13 @@ namespace Avalonia.LeakTests
initialMenuCount = memory . GetObjects ( where = > where . Type . Is < ContextMenu > ( ) ) . ObjectsCount ;
initialMenuItemCount = memory . GetObjects ( where = > where . Type . Is < MenuItem > ( ) ) . ObjectsCount ;
} ) ;
BuildAndShowContextMenu ( window ) ;
BuildAndShowContextMenu ( window ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
Mock . Get ( window . PlatformImpl ) . Invocations . Clear ( ) ;
dotMemory . Check ( memory = >
Assert . Equal ( initialMenuCount , memory . GetObjects ( where = > where . Type . Is < ContextMenu > ( ) ) . ObjectsCount ) ) ;
@ -623,6 +662,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < Path > ( ) ) . ObjectsCount ) ) ;
@ -657,6 +699,9 @@ namespace Avalonia.LeakTests
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < ItemsRepeater > ( ) ) . ObjectsCount ) ) ;
}
@ -725,14 +770,128 @@ namespace Avalonia.LeakTests
Assert . Empty ( lb . ItemContainerGenerator . Containers ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < Canvas > ( ) ) . ObjectsCount ) ) ;
}
}
[Fact]
public void HotKeyManager_Should_Release_Reference_When_Control_Detached ( )
{
using ( Start ( ) )
{
Func < Window > run = ( ) = >
{
var gesture1 = new KeyGesture ( Key . A , KeyModifiers . Control ) ;
var tl = new Window
{
Content = new ItemsRepeater ( ) ,
} ;
tl . Show ( ) ;
var button = new Button ( ) ;
tl . Content = button ;
tl . Template = CreateWindowTemplate ( ) ;
tl . ApplyTemplate ( ) ;
tl . Presenter . ApplyTemplate ( ) ;
HotKeyManager . SetHotKey ( button , gesture1 ) ;
// Detach the button from the logical tree, so there is no reference to it
tl . Content = null ;
tl . ApplyTemplate ( ) ;
return tl ;
} ;
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < Button > ( ) ) . ObjectsCount ) ) ;
}
}
[Fact]
public void HotKeyManager_Should_Release_Reference_When_Control_In_Item_Template_Detached ( )
{
using ( Start ( ) )
{
Func < Window > run = ( ) = >
{
var gesture1 = new KeyGesture ( Key . A , KeyModifiers . Control ) ;
var tl = new Window { SizeToContent = SizeToContent . WidthAndHeight , IsVisible = true } ;
var lm = tl . LayoutManager ;
tl . Show ( ) ;
var keyGestures = new AvaloniaList < KeyGesture > { gesture1 } ;
var listBox = new ListBox
{
Width = 1 0 0 ,
Height = 1 0 0 ,
VirtualizationMode = ItemVirtualizationMode . None ,
// Create a button with binding to the KeyGesture in the template and add it to references list
ItemTemplate = new FuncDataTemplate ( typeof ( KeyGesture ) , ( o , scope ) = >
{
var keyGesture = o as KeyGesture ;
return new Button
{
DataContext = keyGesture ,
[!Button.HotKeyProperty] = new Binding ( "" )
} ;
} )
} ;
// Add the listbox and render it
tl . Content = listBox ;
lm . ExecuteInitialLayoutPass ( ) ;
listBox . Items = keyGestures ;
lm . ExecuteLayoutPass ( ) ;
// Let the button detach when clearing the source items
keyGestures . Clear ( ) ;
lm . ExecuteLayoutPass ( ) ;
// Add it again to double check,and render
keyGestures . Add ( gesture1 ) ;
lm . ExecuteLayoutPass ( ) ;
keyGestures . Clear ( ) ;
lm . ExecuteLayoutPass ( ) ;
return tl ;
} ;
var result = run ( ) ;
// Process all Loaded events to free control reference(s)
Dispatcher . UIThread . RunJobs ( DispatcherPriority . Loaded ) ;
dotMemory . Check ( memory = >
Assert . Equal ( 0 , memory . GetObjects ( where = > where . Type . Is < Button > ( ) ) . ObjectsCount ) ) ;
}
}
private FuncControlTemplate CreateWindowTemplate ( )
{
return new FuncControlTemplate < Window > ( ( parent , scope ) = >
{
return new ContentPresenter
{
Name = "PART_ContentPresenter" ,
[~ContentPresenter.ContentProperty] = parent [ ~ ContentControl . ContentProperty ] ,
} . RegisterInNameScope ( scope ) ;
} ) ;
}
private IDisposable Start ( )
{
void Cleanup ( )
static void Cleanup ( )
{
// KeyboardDevice holds a reference to the focused item.
KeyboardDevice . Instance . SetFocusedElement ( null , NavigationMethod . Unspecified , KeyModifiers . None ) ;