如何检测MouseWheel事件在WPF中结束

时间:2014-04-09 17:57:25

标签: c# wpf

当我滚动鼠标滚轮时会触发几个MouseWheel事件。我正在使用这些事件来缩放图像。

我希望在一系列MouseWheel事件结束时调用方法。我怎么知道它们何时结束?

这是我到目前为止的实现

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
    }
}

2 个答案:

答案 0 :(得分:11)

实际上,由于摩擦轮旋转是无止境的,因此没有特殊事件来通知使用的结束滚动。但是在您的情况下,您可以测试用户是否在短时间内停止滚动。这可以通过一个简单的计时器完成:

    //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();
    }

正如您所见,MouseWheel事件将启动计时器。如果在计时器触发时发生新的MouseWheel事件,它将重新启动计时器。这样,只有在特定时间间隔内没有车轮事件时,计时器才会启动。

答案 1 :(得分:2)

这是一种替代方法,它允许您指定要检测鼠标滚轮移动和灵敏度的UI元素(例如画布,窗口,控件等),这是以毫秒为单位的超时时间。哪个轮被视为非活动(触发自定义停止事件):

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;
            }
        }
    }
}

使用示例:

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"); };
相关问题