Detecting Shaking on Windows Phone

I think it is cool to have a Windows Phone application that the content can be updated by shaking the phone, so I wrote this Class in order to achieve that!!
Detecting Shaking on Windows Phone

Detecting Shaking on Windows Phone

This is how to implement it, the code is well commented and very easy to understand:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;

namespace shakeDetection
{
public partial class MainPage : PhoneApplicationPage
{

//We instanciate the AccelerometerSensorWithShakeDetection class as a prperty in order to be available in all methods for the MainPage class
AccelerometerSensorWithShakeDetection _shakeSensor = new AccelerometerSensorWithShakeDetection();

public MainPage()
{
InitializeComponent();

//in the costructor of the MainPage class, we call the SetUpEvent method, and we pass the MainPage Class as context scope, and the event we want to call
//when the device is Shacked
_shakeSensor.SetUpEvent(this, ShakeDetected);
}

//created a custom event to call the method that contain the code to execute when the device is shaked
private void ShakeDetected(object sender, EventArgs e)
{
//use this method to call MethodToExecWhenTheDeviceIsShaked method in another thread, different from the accelerometer thread
_shakeSensor.DispatcherInvoke(MethodToExecWhenTheDeviceIsShaked);
}

private void MethodToExecWhenTheDeviceIsShaked()
{
myStoryboard.Begin();
//plase here the code you want to exec when the device is shaked
}
private void Rectangle_Tapped(object sender, MouseButtonEventArgs e)
{
myStoryboard.Begin();
}
}
}


This is the class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Devices.Sensors;
using Microsoft.Phone.Controls;

namespace shakeDetection
{

public class AccelerometerSensorWithShakeDetection : IDisposable
{
private const double ShakeThreshold = 0.7;
private readonly Accelerometer _sensor = new Accelerometer();
private AccelerometerReadingEventArgs _lastReading;
private int _shakeCount;
private bool _shaking;
private PhoneApplicationPage ctx;

public AccelerometerSensorWithShakeDetection()
{
var sensor = new Accelerometer();
if (sensor.State == SensorState.NotSupported)
throw new NotSupportedException("Accelerometer not supported on this device");
_sensor = sensor;

}

public void SetUpEvent(PhoneApplicationPage ctx, EventHandler ShakeDetected)
{
this.ctx = ctx;
AssociateEventToAcelerometer(ctx, ShakeDetected);
}

public void DispatcherInvoke(Action actionMethod)
{
ctx.Dispatcher.BeginInvoke(() =>
{
actionMethod();
});
}

public SensorState State
{
get { return _sensor.State; }
}

#region IDisposable Members

public void Dispose()
{
if (_sensor != null)
_sensor.Dispose();
}

#endregion

private event EventHandler ShakeDetectedHandler;

public event EventHandler ShakeDetected
{
add
{
ShakeDetectedHandler += value;
_sensor.ReadingChanged += ReadingChanged;
}
remove
{
ShakeDetectedHandler -= value;
_sensor.ReadingChanged -= ReadingChanged;
}
}

public void Start()
{
if (_sensor != null)
_sensor.Start();
}

public void Stop()
{
if (_sensor != null)
_sensor.Stop();
}

private void ReadingChanged(object sender, AccelerometerReadingEventArgs e)
{
//Code for checking shake detection
if (_sensor.State == SensorState.Ready)
{
AccelerometerReadingEventArgs reading = e;
try
{
if (_lastReading != null)
{
if (!_shaking && CheckForShake(_lastReading, reading, ShakeThreshold) && _shakeCount >= 1)
{
//We are shaking
_shaking = true;
_shakeCount = 0;
OnShakeDetected();
}
else if (CheckForShake(_lastReading, reading, ShakeThreshold))
{
_shakeCount++;
}
else if (!CheckForShake(_lastReading, reading, 0.2))
{
_shakeCount = 0;
_shaking = false;
}
}
_lastReading = reading;
}
catch
{
/* ignore errors */
}
}
}

private void OnShakeDetected()
{
if (ShakeDetectedHandler != null)
ShakeDetectedHandler(this, EventArgs.Empty);
}

private static bool CheckForShake(AccelerometerReadingEventArgs last, AccelerometerReadingEventArgs current, double threshold)
{
double deltaX = Math.Abs((last.X - current.X));
double deltaY = Math.Abs((last.Y - current.Y));
double deltaZ = Math.Abs((last.Z - current.Z));

return (deltaX > threshold && deltaY > threshold) ||
(deltaX > threshold && deltaZ > threshold) ||
(deltaY > threshold && deltaZ > threshold);
}

public void AssociateEventToAcelerometer(PhoneApplicationPage pageContext, EventHandler ShakeDetected)
{
pageContext.Loaded += (sender, args) =>
{
this.ShakeDetected += ShakeDetected;
this.Start();
};
pageContext.Unloaded += (sender, args) =>
{
this.ShakeDetected -= ShakeDetected;
this.Stop();
};
}

}
}