Safe event detachment ‘pattern’ for behaviors
For the past few weeks I’ve been hacking away at my Windows Phone 7 game and noticed something odd. The objective is to intercept moving objects on the screen and drag/flick them to a target – but as the levels progressed interception and movement became ever more difficult and slow. At least that was reported by my #wp7nl fellow members who were kind (or crazy) enough to test drive the game into the higher levels. I won’t mention names here – yet ;-).
I followed the usual pattern for a behavior – at least, I think it is the usual pattern
using System.Windows;
using System.Windows.Interactivity;
namespace SomeNamespace
{
public class DemoBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += AssociatedObjectLoaded;
}
void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
{
// Hook up a bunch of events to the AssociatedObject
}
protected override void OnDetaching()
{
AssociatedObject.Loaded -= AssociatedObjectLoaded;
// Unhook the other events from the AssociatedObject
base.OnDetaching();
}
}
}
I had seen this problem before while programming in WPF and indeed – when I put a breakpoint in the first line of the OnDetaching override it was never called. Apparently Windows Phone 7 has the same problem. So here was my game, happily creating a lot of moving objects with each 1-2 behaviors attached to it listening to a bunch of events. They were never unhooked when the objects were deleted. So within a few levels the game started eating resources like there’s no tomorrow.
I modified my behaviors to try to do a general cleanup not only when OnDetaching is called but also when the AssociatedObject is unloaded. This gave me a pattern which I think might be beneficial to everyone who is working with behaviors in general:
using System.Windows;
using System.Windows.Interactivity;
namespace SomeNamespace
{
public class BetterDemoBehavior : Behavior<FrameworkElement>
{
#region Setup
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += AssociatedObjectLoaded;
AssociatedObject.Unloaded += AssociatedObjectUnloaded;
}
void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
{
// Hook up a bunch of events to the AssociatedObject
}
#endregion
#region Cleanup
private bool _isCleanedUp;
private void Cleanup()
{
if (!_isCleanedUp)
{
_isCleanedUp = true;
AssociatedObject.Loaded -= AssociatedObjectLoaded;
AssociatedObject.Unloaded -= AssociatedObjectUnloaded;
// Unhook the other events from the AssociatedObject
}
}
protected override void OnDetaching()
{
Cleanup();
base.OnDetaching();
}
void AssociatedObjectUnloaded(object sender, RoutedEventArgs e)
{
Cleanup();
}
#endregion
}
}
And because I am not very partial to repetitive work, I created a snippet for this piece of code.
I guess that if both and Windows Phone 7 and WPF have this issue, Silverlight will have it as well. I hope at least this will help people who are, like me, stubborn enough to use Silverlight and MVVMLight to develop games for Windows Phone 7 ;-)
MVP Profile
Try my app HoloATC!
HoloLens 2
Magic Leap 2
Meta Quest
Android phones
Snap Spectacles
Buy me a drink ;)
BlueSky
Mastodon
Discord: LocalJoost#3562