かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

ReactiveProperty v6.0.2 をリリースしました

しました。

Release v6.0.2 · runceel/ReactiveProperty · GitHub

メジャーバージョンが上がってます

ということで、1 つ破壊的変更があります。 これまで WPF では EventToReactiveCommandEventToReactiveProperty を使うのに Blend SDK のアセンブリの Behavior を使用していました。

この Blend SDK は Visual Studio 2019 から同梱されなくなっていて、公式の NuGet パッケージもない状態になりました。そのため、それを置き換える OSS の Behavior のライブラリーである XAML Behaviors for WPF を使用するようにしました。

github.com

そのため、クラス名は同じですが参照元アセンブリや、名前空間が変わっているため、この機能を使用している場合にはコードの変更が必要になります。

更新手順

以下の手順で更新可能です。

  1. ReactiveProperty を v6 以上に更新する
  2. Blend SDK の参照を消す(System.Windows.InteractivityMicrosoft.Expression.Intaractions)
  3. XAML 内の xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"xmlns:i="http://schemas.microsoft.com/xaml/behaviors" に変更する
  4. xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" がある場合も xmlns:i="http://schemas.microsoft.com/xaml/behaviors" に置き換える

小さな新機能

INotifyPropertyChanged インターフェースを実装したクラスの変更通知機能を持ったクラスのプロパティから ReactiveProperty を生成して同期をとるための ToReactivePropertyAsSynchronized のソースからターゲット、ターゲットからソースへの変換ロジックを Rx を使って書けるオーバーロードが追加されています。

例えば ReactivePropertySlim<int>ReactiveProperty<string> で値を変換しつつ同期したいケースで、ReactiveProperty<string> が空文字のときは 0 にして、それ以外のケースでは数字としてパース出来るなら ReactivePropertySlim<int> に書き戻したいとします。こんな感じになります。

public class MainWindowViewModel
{
    public ReactivePropertySlim<int> Source { get; } = new ReactivePropertySlim<int>();
    public ReactiveProperty<string> Target { get; }

    public MainWindowViewModel()
    {
        Target = Source.ToReactivePropertyAsSynchronized(x => x.Value,
            convert: ox => ox.Select(x => x.ToString()), // int -> string
            convertBack: ox => Observable.Merge(
                ox.Where(x => string.IsNullOrEmpty(x)).Select(_ => 0), // 空文字は 0
                ox.Where(x => int.TryParse(x, out _)).Select(x => int.Parse(x)))); // それ以外で数字に変換可能だったら数字にする
    }
}

画面と適当にバインドすると以下のように動きます。Target プロパティを TextBox にバインドして、Source プロパティを TextBlock にバインドしています。

f:id:okazuki:20190726213916g:plain

これまでは ReactiveProperty にバリデーションエラーがある場合のみソースへの変更の反映をスキップするという形しかできませんでしたが、Rx を間に差し込めるようになったので Where などで自由にフィルタリングが出来ます。用途に応じてお使いください。

WPF on .NET Core 3.0 対応

これまでも WPF on .NET Core 3.0 に普通に NuGet から導入可能でしたが、EventToReactivePropertyEventToReactiveCommand は利用できませんでした。 このバージョンから .NET Core 3.0 でも、これらの機能が使えるようにしました。

ReactiveProperty v6 以降と .NET Core 3.0 の WPF のプロジェクトに追加して、Microsoft.Xaml.Behaviors.Wpf パッケージを追加することで使えるようになります。 注意点として、Microsoft.Xaml.Behaviors.Wpf パッケージは、まだ .NET Core 対応のパッケージが出ていないため警告がでます。各自の判断で NU1701 の警告を抑止してお使いください。