Browse Source

Ensure that PerspexObject bindings are unsubbed.

pull/467/head
Steven Kirk 10 years ago
parent
commit
4057670f43
  1. 2
      src/Markup/Perspex.Markup/Data/Plugins/PerspexPropertyAccessorPlugin.cs
  2. 12
      src/Perspex.Base/Collections/InccDebug.cs
  3. 5
      src/Perspex.Base/Collections/PerspexList.cs
  4. 25
      src/Perspex.Base/Diagnostics/INotifyCollectionChangedDebug.cs
  5. 22
      src/Perspex.Base/Diagnostics/IPerspexObjectDebug.cs
  6. 5
      src/Perspex.Base/Perspex.Base.csproj
  7. 21
      src/Perspex.Base/PerspexObject.cs
  8. 2
      src/Perspex.Base/Reactive/WeakPropertyChangedObservable.cs
  9. 3
      src/Perspex.Controls/Control.cs
  10. 5
      tests/Perspex.LeakTests/ControlTests.cs
  11. 5
      tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_PerspexProperty.cs
  12. 3
      tests/Perspex.Styling.UnitTests/SelectorTests_Template.cs

2
src/Markup/Perspex.Markup/Data/Plugins/PerspexPropertyAccessorPlugin.cs

@ -2,9 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.ComponentModel;
using System.Reactive.Linq;
using System.Reflection;
namespace Perspex.Markup.Data.Plugins
{

12
src/Perspex.Base/Collections/InccDebug.cs

@ -1,12 +0,0 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Perspex.Collections
{
public interface InccDebug
{
Delegate[] GetCollectionChangedSubscribers();
}
}

5
src/Perspex.Base/Collections/PerspexList.cs

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using Perspex.Diagnostics;
using Perspex.Platform;
namespace Perspex.Collections
@ -53,7 +54,7 @@ namespace Perspex.Collections
/// </item>
/// </list>
/// </remarks>
public class PerspexList<T> : IPerspexList<T>, IList, InccDebug
public class PerspexList<T> : IPerspexList<T>, IList, INotifyCollectionChangedDebug
{
private List<T> _inner;
private NotifyCollectionChangedEventHandler _collectionChanged;
@ -435,7 +436,7 @@ namespace Perspex.Collections
}
/// <inheritdoc/>
Delegate[] InccDebug.GetCollectionChangedSubscribers() => _collectionChanged?.GetInvocationList();
Delegate[] INotifyCollectionChangedDebug.GetCollectionChangedSubscribers() => _collectionChanged?.GetInvocationList();
/// <summary>
/// Raises the <see cref="CollectionChanged"/> event with an add action.

25
src/Perspex.Base/Diagnostics/INotifyCollectionChangedDebug.cs

@ -0,0 +1,25 @@
// Copyright (c) The Perspex 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.Collections.Specialized;
using Perspex.Collections;
namespace Perspex.Diagnostics
{
/// <summary>
/// Provides a debug interface into <see cref="INotifyCollectionChanged"/> subscribers on
/// <see cref="PerspexList{T}"/>
/// </summary>
public interface INotifyCollectionChangedDebug
{
/// <summary>
/// Gets the subscriber list for the <see cref="INotifyCollectionChanged.CollectionChanged"/>
/// event.
/// </summary>
/// <returns>
/// The subscribers or null if no subscribers.
/// </returns>
Delegate[] GetCollectionChangedSubscribers();
}
}

22
src/Perspex.Base/Diagnostics/IPerspexObjectDebug.cs

@ -0,0 +1,22 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Perspex.Diagnostics
{
/// <summary>
/// Provides a debug interface into <see cref="PerspexObject"/>.
/// </summary>
public interface IPerspexObjectDebug
{
/// <summary>
/// Gets the subscriber list for the <see cref="IPerspexObject.PropertyChanged"/>
/// event.
/// </summary>
/// <returns>
/// The subscribers or null if no subscribers.
/// </returns>
Delegate[] GetPropertyChangedSubscribers();
}
}

5
src/Perspex.Base/Perspex.Base.csproj

@ -43,7 +43,7 @@
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Collections\InccDebug.cs" />
<Compile Include="Diagnostics\INotifyCollectionChangedDebug.cs" />
<Compile Include="Data\AssignBindingAttribute.cs" />
<Compile Include="Data\BindingOperations.cs" />
<Compile Include="Data\InstancedBinding.cs" />
@ -51,6 +51,7 @@
<Compile Include="Data\IndexerDescriptor.cs" />
<Compile Include="Collections\PerspexDictionary.cs" />
<Compile Include="Data\BindingMode.cs" />
<Compile Include="Diagnostics\IPerspexObjectDebug.cs" />
<Compile Include="Diagnostics\PerspexObjectExtensions.cs" />
<Compile Include="AttachedProperty.cs" />
<Compile Include="IStyledPropertyAccessor.cs" />
@ -68,6 +69,7 @@
<Compile Include="Metadata\XmlnsDefinitionAttribute.cs" />
<Compile Include="PerspexObjectExtensions.cs" />
<Compile Include="PropertyMetadata.cs" />
<Compile Include="Reactive\WeakPropertyChangedObservable.cs" />
<Compile Include="StyledProperty.cs" />
<Compile Include="StyledPropertyBase.cs" />
<Compile Include="PerspexPropertyRegistry.cs" />
@ -104,6 +106,7 @@
<Compile Include="Threading\PerspexScheduler.cs" />
<Compile Include="Threading\PerspexSynchronizationContext.cs" />
<Compile Include="Threading\SingleThreadDispatcher.cs" />
<Compile Include="Utilities\IWeakSubscriber.cs" />
<Compile Include="Utilities\MathUtilities.cs" />
<Compile Include="Utilities\TypeUtilities.cs" />
<Compile Include="Utilities\WeakSubscriptionManager.cs" />

21
src/Perspex.Base/PerspexObject.cs

@ -9,6 +9,7 @@ using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Perspex.Data;
using Perspex.Diagnostics;
using Perspex.Threading;
using Perspex.Utilities;
using Serilog;
@ -22,7 +23,7 @@ namespace Perspex
/// <remarks>
/// This class is analogous to DependencyObject in WPF.
/// </remarks>
public class PerspexObject : IPerspexObject, INotifyPropertyChanged
public class PerspexObject : IPerspexObject, IPerspexObjectDebug, INotifyPropertyChanged
{
/// <summary>
/// The parent object that inherited values are inherited from.
@ -40,6 +41,11 @@ namespace Perspex
/// </summary>
private PropertyChangedEventHandler _inpcChanged;
/// <summary>
/// Event handler for <see cref="PropertyChanged"/> implementation.
/// </summary>
private EventHandler<PerspexPropertyChangedEventArgs> _propertyChanged;
/// <summary>
/// A serilog logger for logging property events.
/// </summary>
@ -77,7 +83,11 @@ namespace Perspex
/// <summary>
/// Raised when a <see cref="PerspexProperty"/> value changes on this object.
/// </summary>
public event EventHandler<PerspexPropertyChangedEventArgs> PropertyChanged;
public event EventHandler<PerspexPropertyChangedEventArgs> PropertyChanged
{
add { _propertyChanged += value; }
remove { _propertyChanged -= value; }
}
/// <summary>
/// Raised when a <see cref="PerspexProperty"/> value changes on this object.
@ -456,6 +466,11 @@ namespace Perspex
}
/// <inheritdoc/>
Delegate[] IPerspexObjectDebug.GetPropertyChangedSubscribers()
{
return _propertyChanged?.GetInvocationList();
}
/// <summary>
/// Gets all priority values set on the object.
/// </summary>
@ -519,7 +534,7 @@ namespace Perspex
OnPropertyChanged(e);
property.NotifyChanged(e);
PropertyChanged?.Invoke(this, e);
_propertyChanged?.Invoke(this, e);
if (_inpcChanged != null)
{

2
src/Perspex.Base/Reactive/WeakPropertyChangedObservable.cs

@ -45,7 +45,7 @@ namespace Perspex.Reactive
if (_sourceReference.TryGetTarget(out instance))
{
if (_count == 0)
if (_count++ == 0)
{
WeakSubscriptionManager.Subscribe(
instance,

3
src/Perspex.Controls/Control.cs

@ -12,6 +12,7 @@ using Perspex.Collections;
using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.Data;
using Perspex.Diagnostics;
using Perspex.Input;
using Perspex.Interactivity;
using Perspex.LogicalTree;
@ -542,7 +543,7 @@ namespace Perspex.Controls
child.OnDetachedFromLogicalTree(e);
}
if (((InccDebug)_classes).GetCollectionChangedSubscribers()?.Length > 0)
if (((INotifyCollectionChangedDebug)_classes).GetCollectionChangedSubscribers()?.Length > 0)
{
// TODO: This should be output using a standard logging mechanism.
System.Diagnostics.Debug.WriteLine(

5
tests/Perspex.LeakTests/ControlTests.cs

@ -9,6 +9,7 @@ using Perspex.Collections;
using Perspex.Controls;
using Perspex.Controls.Primitives;
using Perspex.Controls.Templates;
using Perspex.Diagnostics;
using Perspex.Layout;
using Perspex.Styling;
using Perspex.UnitTests;
@ -230,7 +231,7 @@ namespace Perspex.LeakTests
// The TextBox should have subscriptions to its Classes collection from the
// default theme.
Assert.NotEmpty(((InccDebug)textBox.Classes).GetCollectionChangedSubscribers());
Assert.NotEmpty(((INotifyCollectionChangedDebug)textBox.Classes).GetCollectionChangedSubscribers());
// Clear the content and ensure the TextBox is removed.
window.Content = null;
@ -238,7 +239,7 @@ namespace Perspex.LeakTests
Assert.Null(window.Presenter.Child);
// Check that the TextBox has no subscriptions to its Classes collection.
Assert.Null(((InccDebug)textBox.Classes).GetCollectionChangedSubscribers());
Assert.Null(((INotifyCollectionChangedDebug)textBox.Classes).GetCollectionChangedSubscribers());
}
}

5
tests/Perspex.Markup.UnitTests/Data/ExpressionObserverTests_PerspexProperty.cs

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using Perspex.Diagnostics;
using Perspex.Markup.Data;
using Xunit;
@ -24,6 +25,8 @@ namespace Perspex.Markup.UnitTests.Data
var result = await target.Take(1);
Assert.Equal("foo", result);
Assert.Null(((IPerspexObjectDebug)data).GetPropertyChangedSubscribers());
}
[Fact]
@ -39,6 +42,8 @@ namespace Perspex.Markup.UnitTests.Data
Assert.Equal(new[] { "foo", "bar" }, result);
sub.Dispose();
Assert.Null(((IPerspexObjectDebug)data).GetPropertyChangedSubscribers());
}
[Fact]

3
tests/Perspex.Styling.UnitTests/SelectorTests_Template.cs

@ -15,6 +15,7 @@ namespace Perspex.Styling.UnitTests
using System.Reactive;
using System.Reactive.Subjects;
using Collections;
using Diagnostics;
using Controls = Controls.Controls;
public class SelectorTests_Template
@ -124,7 +125,7 @@ namespace Perspex.Styling.UnitTests
var border = (Border)target.Object.VisualChildren.Single();
var selector = new Selector().OfType(templatedControl.Object.GetType()).Class("foo").Template().OfType<Border>();
var activator = selector.Match(border).ObservableResult;
var inccDebug = (InccDebug)styleable.Object.Classes;
var inccDebug = (INotifyCollectionChangedDebug)styleable.Object.Classes;
using (activator.Subscribe(_ => { }))
{

Loading…
Cancel
Save