如何在不阻止UI的情况下向WPF程序添加延迟

时间:2013-04-23 18:44:32

标签: wpf user-interface inotifypropertychanged thread-sleep

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

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

我想要做的是创建一个“超时状态”,也就是说,当某个事件发生时(启动应用程序,单击某个按钮),设备进入状态一段固定时间,然后再回到“准备好”或“闲置”状态。

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

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
    }
}

1 个答案:

答案 0 :(得分:1)

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

尝试将其作为Sleep的替代品而不阻止UI线程:

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

的函数

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

<强> .net45

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

我们让函数返回Task vs void的原因只是让调用者在此函数上需要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状态之后。