【问题标题】:How to add a delay to a WPF program without blocking the UI如何在不阻塞 UI 的情况下向 WPF 程序添加延迟
【发布时间】:2013-04-23 18:44:31
【问题描述】:

我正在构建一个设备模拟器。当它启动时,它需要一些时间来初始化。这在逻辑上表现为打开并立即进入“初始化”状态,并在一段时间后进入“就绪”状态。

我正在使用 MVVM,因此 ViewModel 现在将代表所有设备逻辑。每个可能的状态都有一个由视图呈现的数据触发样式。如果我只是在构建视图模型时设置状态,则视图会以正确的外观呈现。

我要做的是创建一个“超时状态”,即当某些事件发生时(启动应用程序,点击某个按钮),设备进入一个固定时间的状态,然后回退到“就绪”或“空闲”状态。

我考虑过使用睡眠,但睡眠会阻止 UI(他们这么说)。所以我考虑使用线程,但我不知道该怎么做。这是我到目前为止所得到的:

using System.ComponentModel;

namespace EmuladorMiotool {
    public class MiotoolViewModel : INotifyPropertyChanged {
        Estados _estado;

        public Estados Estado {
          get {
              return _estado;
          }
          set {
              _estado = value;
              switch (_estado) {
                  case Estados.WirelessProcurando:
                      // WAIT FOR TWO SECONDS WITHOUT BLOCKING GUI
                      // It should look like the device is actually doing something
                      // (but not indeed, for now)
                      _estado = Estados.WirelessConectado;
                      break;
              }
              RaisePropertyChanged("Estado");
          }
        }

        public MiotoolViewModel() {
            // The constructor sets the initial state to "Searching"
            Estado = Estados.WirelessProcurando;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void RaisePropertyChanged(string propertyName) {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

    }

    public enum Estados {
        UsbOcioso,
        UsbAquisitando,
        UsbTransferindo,
        WirelessNãoPareado,
        WirelessPareado,
        WirelessDesconectado,
        WirelessProcurando,
        WirelessConectado,
        WirelessAquisitando,
        DataLoggerOcioso,
        DataLoggerAquisitando,
        Erro,
        Formatando
    }
}

【问题讨论】:

    标签: wpf user-interface inotifypropertychanged thread-sleep


    【解决方案1】:

    首先在属性(getter / setter)中进行睡眠/异步操作被认为是不好的做法

    在不阻塞 UI 线程的情况下尝试将其作为 Sleep 的替代品:

    创建一个函数将Estado设置为Estados.WirelessProcurando

    假设WirelessProcurando 表示正在初始化,WirelessConectado 表示已初始化

    .net45

    private async Task SetWirelessProcurando(int milliSeconds) {
      Estado = Estados.WirelessProcurando;
      await Task.Delay(milliSeconds);
      Estado = Estados.WirelessConectado;
    }
    

    我们让函数返回 Taskvoid 的原因只是为了让调用者在需要时让调用者 await 在逻辑需要时使用此函数

    如果您不能使用await

    private void SetWirelessProcurando(int milliSeconds) {
      Estado = Estados.WirelessProcurando;
      var tempTask = new Task
        (
        () => {
          Thread.Sleep(milliSeconds);
          System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => Estado = Estados.WirelessConectado));
        },
        System.Threading.Tasks.TaskCreationOptions.LongRunning
        );
      tempTask.Start();
    }
    

    现在,只要您想更改设置器,调用此函数就会立即将状态设置为“Intiialising”,并且在给定的milliSeconds 切换到Initialised 状态之后。

    【讨论】:

    • 我这里是 .NET 4.0,所以我觉得async 不可用,是吗?
    • @heltonbiker 不,它不在 .net4 中 :(。您可以使用我刚刚添加的替代方法,它应该适用于 .net4
    • 另外,如果我在初始化过程运行时尝试get设备状态,它必须返回Estados.WirelessProcurando
    • @heltonbiker 好的,我认为 WirelessProcurando 的意思是初始化状态。初始化时(即延迟后)你希望它进入什么状态
    • @heltonbiker 我已经更新了我的答案,以便在调用时立即将状态设置为 WirelessProcurando,然后在给定的延迟后将状态从主 UI 线程切换为 WirelessConectado。
    猜你喜欢
    • 2020-02-06
    • 2015-11-17
    • 1970-01-01
    • 2017-05-02
    • 1970-01-01
    • 2011-09-01
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    相关资源
    最近更新 更多