C#反复调用函数以自动增加标签的值
这是WPF程序。它上面有一个标签(minuteTimerLabel),该标签显示两位数字,从00、01、02一直到99,以此类推。我希望该标签具有两个功能。首先,当鼠标左键在标签上(模拟点击)时,数字增加1。我已经能够实现这一点。但是我对第二个功能有疑问。
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);
}
}
在标签上按住鼠标左键几秒钟后,数字应自动保持一个一递增。 timerMinute是全局int变量。 使用我当前的代码,整个程序将锁定并且没有任何效果。当我删除while(true)时,按下鼠标时数字只会增加一次。如果我松开鼠标再按一次,它会起作用,但只能再次起作用。
答案 0 :(得分:2)
为避免锁定UI,您需要使用某种形式的异步编码。我建议使用Microsoft的Reactive Framework。
获取“ System.Reactive.Windows.Threading”以获取这些位,并将using System.Reactive.Linq;
添加到代码顶部。
然后您可以执行以下操作:
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();
}
它超级简单,干净。
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();
}
答案 1 :(得分:0)
在这种情况下,您需要绑定两个事件,PreviewMouseDown
和PreviewMouseUp
。然后计算出时间间隔,并以滴答/秒为单位降低标签的值。
赞
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;
}
}
答案 2 :(得分:0)
尝试以下代码:
代码将在另一个线程中运行,而不会阻塞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);
}
}
答案 3 :(得分:0)
非常适合CancellationToken
和异步等待模式
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();
}
如果您想变得棘手,则可以通过更改延迟来增加权重,例如,鼠标按下的次数越多