2017-08-16 1 views
2

Reactive 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); 

は、それは私がより読みやすいと思い1つのパイプライン、で一緒にすべてのロジックを置きます。


別にisMessageVisibleを書き換えることから、私は、メッセージが最初に表示方法を変更したいです。

私はisMessageVisibleをドロップし、プロパティしか持っていません。 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); 

RunWalkCrawlはすべてですs。

+0

偉大な答え。 Rx/UIで効果を発揮するには、考え方を完全に変えなければならないようです。ありがとう。 –

関連する問題