When I scroll mouse wheel several MouseWheel events are fired. And I'm using these events to scale some image.
I want to call a method the moment the series of MouseWheel
events are ended. How can I know when they end?
Here is my implementation so far
private void ModelWindowBorder_MouseWheel(object sender, MouseWheelEventArgs e)
{
intervaltimer = null;
// Do stuff like zooming and etc
CheckEventInterval()
}
private void CheckEventInterval()
{
intervaltimer = new Stopwatch();
intervaltimer .Start();
if (intervaltimer.ElapsedMilliseconds > 50)
{
// Do some other stuff
}
}
Actually as mose wheel rotation is endless there is no special event to notify that the used ended scrolling. However in your case you can just test whether the user stopped scrolling for a short period of time. This can be done with a simple timer:
//Use dispatcher timer to avoid problems when manipulating UI related objects
DispatcherTimer timer;
float someValue = 0;
public MainWindow()
{
InitializeComponent();
timer = new DispatcherTimer();
timer.Tick += timer_Tick;
timer.Interval = TimeSpan.FromMilliseconds(500 /*Adjust the interval*/);
MouseWheel += MainWindow_MouseWheel;
}
void timer_Tick(object sender, EventArgs e)
{
//Prevent timer from looping
(sender as DispatcherTimer).Stop();
//Perform some action
Console.WriteLine("Scrolling stopped (" + someValue + ")");
//Reset for futher scrolling
someValue = 0;
}
void MainWindow_MouseWheel(object sender, MouseWheelEventArgs e)
{
//Accumulate some value
someValue += e.Delta;
timer.Stop();
timer.Start();
}
As you can see MouseWheel event will launch the timer. And if a new MouseWheel event occurs befor the timer fires it will restart the timer. In this way the timer will only fire if there is no wheel events for a specific interval.
Here is an alternative approach, which allows you to specify UI element (e.g. canvas, window, control etc.) for which you'd like to detect mouse wheel movements and sensitivity, which is timeout given in milliseconds, after which wheel is considered as inactive (custom stop event is fired):
public sealed class MouseWheelMonitor : IDisposable
{
private AutoResetEvent _resetMonitorEvent;
private readonly Dispatcher _dispatcher;
private readonly UIElement _canvas;
private readonly int _sensitivity;
private bool _disposed;
private volatile bool _inactive;
private volatile bool _stopped;
public event EventHandler<MouseWheelEventArgs> MouseWheel;
public event EventHandler<EventArgs> MouseWheelStarted;
public event EventHandler<EventArgs> MouseWheelStopped;
public MouseWheelMonitor(UIElement canvas, int sensitivity)
{
_canvas = canvas;
_canvas.MouseWheel += (s, e) => RaiseMouseWheel(e);
_sensitivity = sensitivity;
_dispatcher = Dispatcher.CurrentDispatcher;
_resetMonitorEvent = new AutoResetEvent(false);
_disposed = false;
_inactive = true;
_stopped = true;
var monitor = new Thread(Monitor) {IsBackground = true};
monitor.Start();
}
private void Monitor()
{
while (!_disposed)
{
if (_inactive) // if wheel is still inactive...
{
_resetMonitorEvent.WaitOne(_sensitivity/10); // ...wait negligibly small quantity of time...
continue; // ...and check again
}
// otherwise, if wheel is active...
_inactive = true; // ...purposely change the state to inactive
_resetMonitorEvent.WaitOne(_sensitivity); // wait...
if (_inactive) // ...and after specified time check if the state is still not re-activated inside mouse wheel event
RaiseMouseWheelStopped();
}
}
private void RaiseMouseWheel(MouseWheelEventArgs args)
{
if (_stopped)
RaiseMouseWheelStarted();
_inactive = false;
if (MouseWheel != null)
MouseWheel(_canvas, args);
}
private void RaiseMouseWheelStarted()
{
_stopped = false;
if (MouseWheelStarted != null)
MouseWheelStarted(_canvas, new EventArgs());
}
private void RaiseMouseWheelStopped()
{
_stopped = true;
if (MouseWheelStopped != null)
_dispatcher.Invoke(() => MouseWheelStopped(_canvas, new EventArgs())); // invoked on cached dispatcher for convenience (because fired from non-UI thread)
}
public void Dispose()
{
if(!_disposed)
{
_disposed = true;
DetachEventHandlers();
if (_resetMonitorEvent != null)
{
_resetMonitorEvent.Close();
_resetMonitorEvent = null;
}
}
}
private void DetachEventHandlers()
{
if (MouseWheel != null)
{
foreach (var handler in MouseWheel.GetInvocationList().Cast<EventHandler<MouseWheelEventArgs>>())
{
MouseWheel -= handler;
}
}
if (MouseWheelStarted != null)
{
foreach (var handler in MouseWheelStarted.GetInvocationList().Cast<EventHandler<EventArgs>>())
{
MouseWheelStarted -= handler;
}
}
if (MouseWheelStopped != null)
{
foreach (var handler in MouseWheelStopped.GetInvocationList().Cast<EventHandler<EventArgs>>())
{
MouseWheelStopped -= handler;
}
}
}
}
And the usage sample:
var monitor = new MouseWheelMonitor(uiElement, 1000);
monitor.MouseWheel += (s, e) => { Debug.WriteLine("mouse wheel turned"); };
monitor.MouseWheelStarted += (s, e) => { Debug.WriteLine("mouse wheel started"); };
monitor.MouseWheelStopped += (s, e) => { Debug.WriteLine("mouse wheel stopped"); };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With