LoginSignup
12
14

More than 3 years have passed since last update.

ReactiveProperty 5.2.0の新機能Awaitableを使ってみた

Last updated at Posted at 2018-08-02

概要

ReactiveProeprty 5.2.0の新機能AwaitableなReactivePropertyを使ってみました。

ReactivePropertyの説明自体は下記を参照ください。
https://blog.okazuki.jp/entry/2015/12/05/221154

AwaitableなReactivePropertyとは

ReactivePropertyがAwaitable パターンを実装したことで、awaitで値の変更を待機することができるようになりました。
今までもSubscribeで値の変更を購読することはできましたが、

  • 1度だけ購読して何かしたい
  • 値の変更を待機して、次の処理を続けて書きたい

といった時には少々手間でした。
Awaitableパターンが実装されたことにより、下記のような形で値の変更を待機することができます。

var newValue = await MyReactiveProperty;

他にもSubscribeとの相違点としては、ReactivePropertyをSubscribeするとModeRaiseLatestValueOnSubscribeならばすぐに値が返ってきますが、
awaitした場合は、Modeに関係なく変更するまで待機します。

なお、Awaitableになったのは狭義のReactivePropertyだけでなく、
(ReadOnly)ReactiveProperty(Slim)と(Async)ReactiveCommand(Generic)もです。
つまりだいたい全部です。

ReactiveCommandの場合はCanExcuteの変化ではなく、Excute呼び出しを待機して、返り値はExcute呼び出し時の引数です。

注意点として、今回のバージョンには破壊的変更が含まれています。
あまり実用的ではないのですが、5.1以前でもawaitで待機することは可能でした。
この場合はReactivePropertyがDisposeされるまで待機して、最後の値が返ってきます。
これはReactivePropertyというよりも、IObsevable<T>の機能です。

デモ

デモプログラムを作ってみました。
WPFでファイルの変更を監視して、それをTextBoxに表示するアプリケーションを作ります。
ボタン押下後に監視を開始して、変更されたら1度だけTextBoxに反映させます。

デモ実行結果

起動時
スクリーンショット 2018-08-02 22.18.07.png

Button押下後、awaitで待機中はボタンが無効になっています。
スクリーンショット 2018-08-02 22.15.47.png

メモ帳で監視対象のファイルを変更します。
スクリーンショット 2018-08-02 22.16.13.png

TextBoxに入力された文字が大文字化されて入ります。以降はファイルを変更しても反映されません。
image.png

ViewModel

ViewModelではAsyncReactiveCommandを用意して、コマンドのSubscribe内でmodelのReactivePropertySlimの変更をawaitで待機しています。
待機している間、コマンドのCanExcuteはfalseになります。
ReactivePropertySlimが変更されたら、その値を大文字化して、VM内のReactivePropertyに反映させます。

MainWindowViewModel.cs
class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private Model model = new Model();

    public ReactiveProperty<string> Name { get; } = new ReactiveProperty<string>("TARO");

    public AsyncReactiveCommand UpdateWaitLoadCommand { get; } = new AsyncReactiveCommand();

    public MainWindowViewModel()
    {
        UpdateWaitLoadCommand.Subscribe(DoSomeAsync);
    }

    private async Task DoSomeAsync()
    {
        model.StartLoad();
        string loadText = await model.LoadedText; //ReactivePropertyの変更を待つ

        Name.Value = loadText.ToUpper();
    }
}

Model

Modelでは一定時間ごとにファイルを見て、Model内のReactivePropertySlimに反映しています。

Model.cs
class Model
{
    public ReactivePropertySlim<string> LoadedText { get; } = new ReactivePropertySlim<string>("");

    private const string inputPath = "inputText.txt";
    private Timer timerLoad = new Timer();

    public Model()
    {
        timerLoad.Elapsed += TimerLoad_Elapsed;
    }

    private void TimerLoad_Elapsed(object sender, ElapsedEventArgs e)
    {
        string loadedText = File.ReadAllText(inputPath);
        LoadedText.Value = loadedText;
    }

    /// <summary>
    /// ファイル監視の開始
    /// </summary>
    internal void StartLoad()
    {
        using (File.Create(inputPath)) { }

        timerLoad.Start();
    }
}

View

ViewではVMのReactivePropertyAsyncReactiveCommandにBindingしています。

MainWindow.xaml
<Window
    x:Class="TestReactiveProperty52.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestReactiveProperty52"
    Width="300"
    Height="150">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <StackPanel>
        <TextBox Text="{Binding Name.Value, UpdateSourceTrigger=PropertyChanged}" />
        <Button Command="{Binding UpdateWaitLoadCommand}" Content="ファイルが変更されるのを待って反映" />
    </StackPanel>
</Window>

参考

https://runceel.github.io/ReactiveProperty/advanced/awaitable/#awaitable
https://ufcpp.net/study/csharp/sp5_awaitable.html

環境

VisualStudio2017
.NET Framework 4.7.1
C#7.1
ReactiveProperty 5.2.0

12
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
14