2017-08-16 51 views
2

我正在使用反應式UI,我想在完成一個過程後顯示一條消息,並在一段時間(4秒)後隱藏此消息。如果消息比隱藏時間快,則應重置超時,以便在最後一條消息顯示/更新後的4秒後始終隱藏消息。如果最後一條消息與之前的消息相同,則隱藏時間也應該延長。RxUI.NET - 在一段時間後隱藏消息

目前我有這個代碼,這是我想要的,但它看起來太麻煩了。我只是在試用RxUI,所以大部分時間我都不知道自己在做什麼。有沒有更好的方法來實現這個目標?

public class MainViewModel: ReactiveObject 
{ 
    // Message to be shown. 
    private string message; 
    public string Message { get => message; set => this.RaiseAndSetIfChanged(ref message, value); 

    // Flag for the UI, if the message panel should be visible. 
    private ObservableAsPropertyHelper<bool> isMessageVisible; 
    public bool IsMessageVisible => isMessageVisible.Value; 

    // Command that runs async process, the result is the message to be shown. 
    public ReactiveCommand<Unit, string> Run { get; private set; } 

    public MainViewModel() 
    {   
    var msg = this.WhenAnyValue(x => x.Message, x => !string.IsNullOrEmpty(x)); 

    // If message changes, after 4 seconds return false, causing hiding the message panel. 
    var hide = msg.Select(x => false).Throttle(TimeSpan.FromSeconds(4), RxApp.MainThreadScheduler); 

    // Merge both sequences into one output property. 
    Observable.Merge(msg, hide).ToProperty(this, x => x.IsMessageVisible, out isMessageVisible); 

    Run = ReactiveCommand.CreateFromObservable(() => Observable.StartAsync(Process)); 

    // Merge various message sources and set message property. Set Message = null to force property change. 
    Observable.Merge(Run, Run.ThrownExceptions.Select(x => x.Message)).Subscribe(x => { Message = null; Message = x; });  
    }  
    ... 
} 

回答

3

個人而言,我會宣佈isMessageVisible這樣的:

isMessageVisible = this 
    .WhenAnyValue(x => x.Message, x => !string.IsNullOrEmpty(x)) 
    .Select(showMessage => Observable.Return(showMessage).Concat(Observable.Return(false).Delay(4, RxApp.MainThreadScheduler))) 
    .Switch() 
    .ToProperty(this, x => x.IsMessageVisible); 

它把所有的邏輯集中在一個管道,我認爲這是更具可讀性。


除了重寫isMessageVisible,我會改變消息如何顯示在第一位。

我會掉落isMessageVisible,只有Message屬性。當string.IsNullOrEmpty(Message) == true隱藏UI中的消息時,以及string.IsNullOrEmpty(Message) == false顯示UI。這將是這樣與RxUI綁定:

this.OneWayBind(ViewModel, vm => vm.Message, v => v.Message.Text, message => !string.IsNullOrWhitespace(message)); 

然後我會做到這一點的視圖模型:

public class MainViewModel: ReactiveObject 
{ 
    // Message to be shown. 
    private ObservableAsPropertyHelper<string> message; 
    public string Message => message.Value; 

    // Command that runs async process, the result is the message to be shown. 
    public ReactiveCommand<Unit, string> Run { get; private set; } 

    public MainViewModel() 
    { 
     Run = ReactiveCommand.CreateFromObservable(() => Observable.StartAsync(Process)); 

     // Merge various message sources and set message property. 
     message = Observable.Merge(Run, Run.ThrownExceptions.Select(x => x.Message)) 
      .Select(msg => Observable.Return(msg).Concat(Observable.Return("").Delay(4, RxApp.MainThreadScheduler))) // 1 
      .Switch() // 2 
      .ToProperty(this, x => x.Message); 
    } 
} 
  1. 這將立即返回新的消息,然後返回一個空字符串4秒後
  2. 這隻會訂閱Select返回的最新可觀察值。如果有新的消息被髮送以前觀察到的將不會發送空字符串

如果你有多個命令返回的信息,你可以添加一個方便的功能,以減少代碼量:

private IObservable<string> CreateMessageStream(params ReactiveCommand<Unit, string> commands) 
    => Observable.Merge(commands.SelectMany(command => new IObservable<string>[] { command, command.ThrownExceptions.Select(x => x.Message) })) 
     .Select(msg => Observable.Return(msg).Concat(Observable.Return("").Delay(4, RxApp.MainThreadScheduler))) 
     .Switch() 

然後你可以聲明message這樣的:

message = CreateMessageStream(Run, Walk, Crawl) 
    .ToProperty(this, x => x.Message); 

RunWalkCrawlReactiveCommand s。

+0

很好的答案。似乎人們必須徹底改變心態才能在Rx/UI中發揮作用。謝謝。 –