Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
650 views
in Technique[技术] by (71.8m points)

user interface - How to add a delay to a WPF program without blocking the UI

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.

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.

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
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

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

Create a function to set Estado to Estados.WirelessProcurando

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

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

If you cannot use 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();
}

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...