2014-04-09 18 views
5

Quando si scorre la rotellina del mouse, vengono attivati ​​più eventi MouseWheel. E sto usando questi eventi per ridimensionare alcune immagini.Come rilevare l'evento MouseWheel terminato in WPF

Voglio chiamare un metodo nel momento in cui la serie di eventi MouseWheel è terminata. Come posso sapere quando finiscono?

Qui è la mia realizzazione finora

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

non v'è alcun evento built-in per questa situazione. Forse questo ti aiuta: http://stackoverflow.com/questions/21234210/how-to-determine-when-the-scrollviewer-has-ended-scrolling – MUG4N

+0

Sì. La rotellina del mouse non ha fisicamente alcuna idea di avvio o arresto: è uno stepper. Quando fa clic, fa clic. Questo è diverso da tutti gli altri elementi che per esempio danno una distanza. – TomTom

+1

Un cronometro non è un timer. L'avvio di un nuovo cronometro e il controllo immediato della proprietà ElapsedMilliseconds restituiscono sempre un valore * molto * piccolo, forse sempre zero. Il tuo "Fai del materiale" non verrà quindi mai eseguito. Fallo come mostrato nella risposta. – Clemens

risposta

9

In realtà, come la rotazione della ruota Mose è infinita non c'è evento speciale per notificare che la utilizzato conclusa scorrimento. Tuttavia nel tuo caso puoi semplicemente verificare se l'utente ha smesso di scorrere per un breve periodo di tempo. Questo può essere fatto con un semplice 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(); 
    } 

Come si può vedere, l'evento MouseWheel avvierà il timer. E se si verifica un nuovo evento MouseWheel prima che il timer funzioni, riavvia il timer. In questo modo il timer scatterà solo se non ci sono eventi ruota per un intervallo specifico.

+0

Grazie Didier, In realtà stavo provando questo con StopWatch() ma non verrà eseguito. Puoi guardare il mio codice? – Vahid

+1

Il cronometro è in pratica utilizzato per misurare il tempo. In questo caso la statistica if è subito dopo Start(), quindi il tempo trascorso è quasi pari a 0. In realtà non è possibile testare l'estremità di MouseWheel all'interno del gestore di eventi MouseWheel. In questo caso è ancora possibile utilizzare i cronometri ma è necessario eseguire il test in un tipo di gestore di eventi ripetuto come CompositionTarget.Rendering. – Dmitry

+0

Grazie mille Didier, mi hai aiutato molto e il tuo codice funziona davvero bene. – Vahid

1

Ecco un approccio alternativo, che consente di specificare l'elemento dell'interfaccia utente (ad esempio tela, finestra, controllo ecc.) Per il quale si desidera rilevare i movimenti e la sensibilità della rotellina del mouse, che è il timeout espresso in millisecondi, dopo di che ruota è considerata come non attiva (evento di arresto personalizzato viene licenziato):

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

e il campione di utilizzo:

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"); }; 
Problemi correlati