如何在不阻止UI的情况下向WPF程序添加延迟 [英] How to add a delay to a WPF program without blocking the UI

查看:94
本文介绍了如何在不阻止UI的情况下向WPF程序添加延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建设备模拟器.当启动时,它需要一些时间来初始化.从逻辑上讲,这可以通过打开电源并立即进入初始化"状态,然后在一段时间后进入就绪"状态来表示.

I am building a device emulator. When it starts, it takes some time for it to initialized. This would be logically represented by being turned on and going immediately to an "Initialization" state, and after some time it goes to "Ready" state.

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

I am using MVVM, so the ViewModel will for now represent all the device logic. Each of the possible states have a datatriggered style to be rendered by the View. If I just set the state when I build the viewmodel, the view renders with the correct appearance.

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

What I want to do is to create a "timeout state", that is, when some event occurs (starting the application, clicking a certain button), the device enters a state for a fixed time, and then falls back to the "ready", or "idle" state.

我考虑过使用Sleep,但是sleep阻止了UI(所以他们说).所以我考虑使用线程,但是我不确定该怎么做.这是到目前为止我得到的:

I thought about using Sleep, but sleep blocks the UI (so they say). So I think about using Threads, but I am not sure how to do it. This is what I have got so far:

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

推荐答案

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

Firstly having a Sleep / Async operation in a property (getter / setter) is considered bad-practice

尝试此操作代替Sleep而不阻塞UI线程:

Try this as a replacement for Sleep without blocking the UI thread:

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

Create a function to set Estado to Estados.WirelessProcurando

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

Assuming WirelessProcurando means Initialising and WirelessConectado means Initialised

.net45 :

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

我们让函数返回Task vs void的原因是,如果逻辑上需要的话,让调用方在需要此函数时调用await

The reason we have the function return a Task vs void is just to let the caller if required await on this function if the logic demands it accordingly

如果无法使用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状态之后.

Now calling this function whenever you want to change the setter will immediately set the state to "Intiialising" and after the given milliSeconds switch to the Initialised state.

这篇关于如何在不阻止UI的情况下向WPF程序添加延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆