简体   繁体   中英

How to increase number label when holding down mouse button?

C# Calling a function repeatedly to increase value of label automatically

This is a WPF program. It has a label on it (minuteTimerLabel) that displays a two digit number, starting from 00, 01, 02 and so on up to 99. I want two features from this label. First, when the left mouse button goes up on the label (simulating a click), the number increases by 1. I have been able to implement this. But I have problem with the second feature.

    private void MinuteTimerLabel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        while(true)
        {
            if (timerMinute == 99)
            {
                return;
            }
            timerMinute += 1;
            minuteTimerLabel.Content = String.Format("{0:00}", timerMinute);
            Thread.Sleep(250);
        }
    }

When the left mouse button is held down on the label for a few seconds, the number should keep increasing one by one automatically. timerMinute is a global int variable. With my current code, the entire program locks up and nothing works. When I remove the while(true), number increases only once when pressing mouse down. If I release the mouse and press again, it works but again only once.

To avoid locking up the UI you need to use some form of async coding. I'd suggest using Microsoft's Reactive Framework.

NuGet "System.Reactive.Windows.Threading" to get the bits and add using System.Reactive.Linq; to the top of your code.

Then you can do this:

    private IDisposable _subscription = null;

    private void MinuteTimerLabel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _subscription =
            Observable
                .Interval(TimeSpan.FromMilliseconds(250.0))
                .Select(x => String.Format("{0:00}", x))
                .ObserveOnDispatcher()
                .Subscribe(x => MinuteTimerLabel.Content = x);
    }

    private void MinuteTimerLabel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        _subscription.Dispose();
    }

It's super simple and super clean.


private IDisposable _subscription = null;

private int _counter = 0;

private void MinuteTimerLabel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    _subscription =
        Observable
            .Interval(TimeSpan.FromMilliseconds(250.0))
            .Select(x => String.Format("{0:00}", x))
            .ObserveOnDispatcher()
            .Subscribe(x => MinuteTimerLabel.Content = _counter++ % 100);
}

private void MinuteTimerLabel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    _subscription.Dispose();
}

You need to bind couple of event in this case, PreviewMouseDown and PreviewMouseUp . Then calculate time different between it and increament the value for lable on ticks/secs.

Like this

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        PreviewMouseDown += Window3_PreviewMouseDown;
        PreviewMouseUp += Window3_PreviewMouseUp;
    }

    DateTime mouseDown;
    private void Window3_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        mouseDown = DateTime.Now;
    }

    private void Window3_PreviewMouseUp(object sender, MouseButtonEventArgs e)
    {
        var seconds = DateTime.Now.Subtract( mouseDown ).Seconds;

        //Condition code goes here..
        minuteTimerLabel.Content = seconds;
    }
}

Try the below code:

The code will run in the another thread un-blocking the Main Thread .

private void MinuteTimerLabel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    new Thread(Timer).Start();
}

private void Timer() {
    while(true)
    {
        if (timerMinute == 99)
        {
            return;
        }
        timerMinute += 1;
        minuteTimerLabel.Content = String.Format("{0:00}", timerMinute);
        Thread.Sleep(250);
    }
}

Good fit for a CancellationToken and Async Await Pattern

private CancellationTokenSource _cs;
private int _timerMinute =0;

private async void Label1_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
   _cs?.Cancel();
   _cs?.Dispose();
   _cs = new CancellationTokenSource();
   try
   {
      while (!_cs.Token.IsCancellationRequested)
      {
         await Task.Delay(200, _cs.Token);

         Label1.Content = $"{++_timerMinute:00}";
      }
   }
   catch (OperationCanceledException) {}
}

private void Label1_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
   _cs?.Cancel();
   _cs?.Dispose();
}

Also if you wanted to be tricky you could add weight to it the more the mouse is down, by altering the delay

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM