【问题标题】:C# WPF - Display texts using delaysC# WPF - 使用延迟显示文本
【发布时间】:2016-08-30 06:23:37
【问题描述】:

以下案例

按下按钮

显示文本框“订购成功”

延迟 2 秒仍显示文字

延迟结束,文本更改/消失为“放置您的筹码”

问题:

使用 Thread Sleep 会在显示文本之前冻结整个 UI,延迟后仅显示第二个文本。有趣的是,我在更改文本后播放的声音会播放但没有显示文本。

使用 Task (async/delay/await),它不会等待延迟,而是连续显示两者,因此第一个文本很短的时间,然后立即更改为第二个文本。

使用任务(等待)程序崩溃。

使用 Timer 与使用 Task 具有相同的效果(异步或/和延迟)。

使用 while (time, 2nd time with +2seconds) 现在只是将新时间推入时间,如果时间结束,它就完成了,但与线程睡眠具有相同的效果 - 整个 UI 冻结。


也许有趣的是,有计时器一直在后台运行。

我尝试了很多我在这里找到的版本,但没有一个有效 - 也许它与 WPF 有关,所以我现在问是否有人有 WPF 延迟的解决方案。

代码

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

【问题讨论】:

标签: c# wpf user-interface task delay


【解决方案1】:

(使用 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";
}

【讨论】:

  • WPF 似乎没有 Invoke/MethodInvoker,因为它没有向我显示使用的任何解决方案?
  • 抱歉 - 我错过了 WPF 部分。尝试 System.Windows.Threading.Dispatcher.Invoke 代替 Invoke(new MethodInvoker())
  • 是的,也找到了 Dispatcher.Invoke,但现在想替换 MethodInvoker,看来我需要使用 Action 委托。
  • 当我使用 5000 时,它的“延迟”甚至不到 1 秒。所以它仍然会立即使用您的代码:/
  • 好吧,抱歉,它可以工作 - 另一个程序员在另一个地方使用“放置你的芯片”文本,它会覆盖我/你的代码。
【解决方案2】:

在这种情况下,您可以尝试使用 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】:

System.Threading.Timer 的最小示例。还使用INotifyPropertyChanged Interface 通过WPF Data Bindings 更新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>

代码:

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

【讨论】:

    猜你喜欢
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 2015-08-23
    • 2016-04-19
    • 2013-02-13
    • 1970-01-01
    • 2022-01-19
    • 2016-10-17
    相关资源
    最近更新 更多