Following case
Button pressed
Showing Textbox "Successfully ordered"
显示文本框“已成功订购”
Delay 2 seconds still showing text
延迟2秒仍显示文字
Delay is over and text changes/disappears to "Place your chip"
延迟结束,文字更改/消失为“放置芯片”
Problem:
Using Thread Sleep it freezes whole UI before showing the Text and just the 2nd text appears after the delay. Interesting is, that a sound I play after changing the text is played but the text isn't shown.
使用Thread Sleep它会在显示Text之前冻结整个UI,并且在延迟之后只显示第二个文本。有趣的是,播放改变文本后播放的声音但未显示文本。
Using Task (async/delay/await) it doesn't wait for the delay and just shows both in a row, so first text for a really short time and then instantly changing to 2nd text.
使用Task(async / delay / await)它不等待延迟并且只显示两行,所以第一个文本在很短的时间内然后立即变为第二个文本。
Using Task (wait) the program crashes.
使用任务(等待)程序崩溃。
Using Timer it has the same effect as using Task (async or/and delayed).
使用Timer它与使用Task(异步或/和延迟)具有相同的效果。
Using while (time, 2nd time with +2seconds) now just pushing new time into time and if time is over it's finished, but has the same effect as Thread Sleep - whole UI freezes.
使用while(时间,第二次+2秒)现在只是将新时间推入时间,如果时间结束,它已经完成,但与Thread Sleep具有相同的效果 - 整个UI冻结。
Maybe it's interesting to know, that there are timers running in the background the whole time.
I tried many version I found here, but none did work - maybe it's about WPF, so I'm asking right now if someone has a solution for WPF delays.
我尝试了很多我在这里找到的版本,但没有一个可以工作 - 也许是关于WPF,所以我现在问,如果有人有WPF延迟的解决方案。
Code
private void SendWithDelay()
{
// close(); // Sets text back to "place your chip" but for here:
tbPlace.Text = "Place your chip";
}
private void changeVisibilityForDelay()
{
// called by pressed button
tbPlace.Text = "Successfully ordered";
tbPlace.Visibility = Visibility.Visible;
Task.Delay(2000).ContinueWith(t => SendWithDelay(), TaskScheduler.FromCurrentSynchronizationContext());
}
3 个解决方案
#1
1
(using System.Windows.Threading;)
Something like:
(使用System.Windows.Threading;)类似于:
private void startTimer(){
Thread timerThread = new Thread(runTimer);
timerThread.Start();
}
private async void runTimer(){
await Task.Delay(2000);
Dispatcher.BeginInvoke(new Action(() => updateScreen()));
}
private void updateScreen(){
TextBox1.Text = "This is delayed";
}
#2
1
You can try with DispatcherTimer in this case. Please try the following sample add the two one button and one text box. in the code behind add
在这种情况下,您可以尝试使用DispatcherTimer。请尝试以下示例添加两个按钮和一个文本框。在后面添加的代码中
DispatcherTimer obj = new DispatcherTimer();
DispatcherTimer obj = new DispatcherTimer();
private void button_Click(object sender, RoutedEventArgs e)
{
textBox.Text = "Successfully ordered";
obj.Interval = new TimeSpan(0, 0, 2);
obj.Start();
obj.Tick += Obj_Tick;
}
private void Obj_Tick(object sender, EventArgs e)
{
textBox.Text = "Place your chip";
obj.Stop();
}
#3
1
Minimal example with System.Threading.Timer. Also uses INotifyPropertyChanged Interface to update changes in UI via WPF Data Bindings. XAML code:
System.Threading.Timer的最小示例。还使用INotifyPropertyChanged接口通过WPF数据绑定更新UI中的更改。 XAML代码:
<Window x:Class="WpfTimerExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen" Title="WPF and System.Threading.Timer">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical">
<TextBlock Text="Text is: " />
<TextBlock Text="{Binding Text}" />
<TextBlock Text="TimeDiff: " />
<TextBlock Text="{Binding TimeDiff}" />
</StackPanel>
<StackPanel Grid.Row="1">
<Button Name="btnTimerExample" Content="Click to start Timer example"
Click="btnTimerExample_Click"/>
</StackPanel>
</Grid>
</Window>
Code:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;
namespace WpfTimerExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
readonly TimeSpan TIMER_DUE_TIME = TimeSpan.FromSeconds(2);
readonly TimeSpan TIMER_PERIOD = TimeSpan.FromMilliseconds(-1);
DateTimeOffset _timeWhenButtonClicked;
DateTimeOffset _timeWhenTimerFired;
Timer _timer;
string _Text;
TimeSpan _TimeDiff;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public string Text
{
get { return _Text; }
set { _Text = value; PropertyChanged(this, new PropertyChangedEventArgs("Text")); }
}
public TimeSpan TimeDiff
{
get { return _TimeDiff; }
set { _TimeDiff = value; PropertyChanged(this, new PropertyChangedEventArgs("TimeDiff")); }
}
public MainWindow()
{
DataContext = this;
Text = "Successfully ordered";
InitializeComponent();
}
private void btnTimerExample_Click(object sender, RoutedEventArgs e)
{
Text = "Successfully ordered";
TimeDiff = TimeSpan.Zero;
_timeWhenButtonClicked = DateTimeOffset.UtcNow;
// If there is no timer
if (_timer == null) {
// Create and start timer.
// Call TimerHandler just one time after 2 seconds
_timer = new Timer(TimerHandler, null, TIMER_DUE_TIME, TIMER_PERIOD);
}
else // if exist, just restart it
_timer.Change(TIMER_DUE_TIME, TIMER_PERIOD);
}
private void TimerHandler(object state)
{
_timeWhenTimerFired = DateTimeOffset.UtcNow;
Text = "Place your chip";
TimeDiff = _timeWhenTimerFired - _timeWhenButtonClicked;
}
protected override void OnClosed(EventArgs e)
{
if (_timer != null)
_timer.Dispose();
}
}
}
#1
1
(using System.Windows.Threading;)
Something like:
(使用System.Windows.Threading;)类似于:
private void startTimer(){
Thread timerThread = new Thread(runTimer);
timerThread.Start();
}
private async void runTimer(){
await Task.Delay(2000);
Dispatcher.BeginInvoke(new Action(() => updateScreen()));
}
private void updateScreen(){
TextBox1.Text = "This is delayed";
}
#2
1
You can try with DispatcherTimer in this case. Please try the following sample add the two one button and one text box. in the code behind add
在这种情况下,您可以尝试使用DispatcherTimer。请尝试以下示例添加两个按钮和一个文本框。在后面添加的代码中
DispatcherTimer obj = new DispatcherTimer();
DispatcherTimer obj = new DispatcherTimer();
private void button_Click(object sender, RoutedEventArgs e)
{
textBox.Text = "Successfully ordered";
obj.Interval = new TimeSpan(0, 0, 2);
obj.Start();
obj.Tick += Obj_Tick;
}
private void Obj_Tick(object sender, EventArgs e)
{
textBox.Text = "Place your chip";
obj.Stop();
}
#3
1
Minimal example with System.Threading.Timer. Also uses INotifyPropertyChanged Interface to update changes in UI via WPF Data Bindings. XAML code:
System.Threading.Timer的最小示例。还使用INotifyPropertyChanged接口通过WPF数据绑定更新UI中的更改。 XAML代码:
<Window x:Class="WpfTimerExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen" Title="WPF and System.Threading.Timer">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical">
<TextBlock Text="Text is: " />
<TextBlock Text="{Binding Text}" />
<TextBlock Text="TimeDiff: " />
<TextBlock Text="{Binding TimeDiff}" />
</StackPanel>
<StackPanel Grid.Row="1">
<Button Name="btnTimerExample" Content="Click to start Timer example"
Click="btnTimerExample_Click"/>
</StackPanel>
</Grid>
</Window>
Code:
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;
namespace WpfTimerExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
readonly TimeSpan TIMER_DUE_TIME = TimeSpan.FromSeconds(2);
readonly TimeSpan TIMER_PERIOD = TimeSpan.FromMilliseconds(-1);
DateTimeOffset _timeWhenButtonClicked;
DateTimeOffset _timeWhenTimerFired;
Timer _timer;
string _Text;
TimeSpan _TimeDiff;
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public string Text
{
get { return _Text; }
set { _Text = value; PropertyChanged(this, new PropertyChangedEventArgs("Text")); }
}
public TimeSpan TimeDiff
{
get { return _TimeDiff; }
set { _TimeDiff = value; PropertyChanged(this, new PropertyChangedEventArgs("TimeDiff")); }
}
public MainWindow()
{
DataContext = this;
Text = "Successfully ordered";
InitializeComponent();
}
private void btnTimerExample_Click(object sender, RoutedEventArgs e)
{
Text = "Successfully ordered";
TimeDiff = TimeSpan.Zero;
_timeWhenButtonClicked = DateTimeOffset.UtcNow;
// If there is no timer
if (_timer == null) {
// Create and start timer.
// Call TimerHandler just one time after 2 seconds
_timer = new Timer(TimerHandler, null, TIMER_DUE_TIME, TIMER_PERIOD);
}
else // if exist, just restart it
_timer.Change(TIMER_DUE_TIME, TIMER_PERIOD);
}
private void TimerHandler(object state)
{
_timeWhenTimerFired = DateTimeOffset.UtcNow;
Text = "Place your chip";
TimeDiff = _timeWhenTimerFired - _timeWhenButtonClicked;
}
protected override void OnClosed(EventArgs e)
{
if (_timer != null)
_timer.Dispose();
}
}
}