ReactiveUI/Xamarin.MacのNSTextFieldにバインドする

提供: MonoBook
移動: 案内検索

ReactiveUIのビューモデルをXamarin.MacのNSTextFieldにバインドする場合には一筋縄ではいなかいようだ。 単純にReactiveWindowControllerクラスのBindメソッドやOneWayBindメソッドでバインドしただけではまったく反応してくれなくて困った。 そんな中キーボードを強打しながらGitHubを徘徊していたところ見事に解決策を発見した[1]

    using System;
    using System.ComponentModel;
    using System.Reactive;
    using System.Reactive.Concurrency;
    using System.Reactive.Linq;
    using System.Reactive.Subjects;
    using Foundation;
    using AppKit;
    using ReactiveUI;
 
    public partial class MainWindowController : ReactiveWindowController, IViewFor<MainViewModel>
    {
        // 〜〜〜中略〜〜〜
 
        MainViewModel _viewModel;
 
        public MainViewModel ViewModel { 
            get { return _viewModel; }
            set { this.RaiseAndSetIfChanged(ref _viewModel, value); }
        }
 
        object IViewFor.ViewModel
        {
            get { return ViewModel; }
            set { ViewModel = (MainViewModel)value; }
        }
 
        // 〜〜〜ここまではよくある定型〜〜〜
 
        IObservable<Unit> hookTextField(NSTextField textField)
        {
            var ret = new Subject<Unit>();
            textField.Delegate = new BlockDidChangeTextFieldDelegate(() => ret.OnNext(Unit.Default));
            return ret;
        }
 
        class BlockDidChangeTextFieldDelegate : NSTextFieldDelegate
        {
            Action block;
            public BlockDidChangeTextFieldDelegate(Action block) { this.block = block; }
            public override void Changed(NSNotification notification) { block(); }
        }
 
        public override void WindowDidLoad()
        {
            base.WindowDidLoad();
 
            // ---- バインド ----
 
            // よくあるこの記法では動かない
            //this.Bind(ViewModel, vm => vm.FirstName, v => v.FirstName.StringValue);
 
            // hookTextFieldが重要だった
            this.Bind(ViewModel, vm => vm.FirstName, v => v.FirstName.StringValue, hookTextField(FirstName));
            this.Bind(ViewModel, vm => vm.LastName , v => v.LastName.StringValue , hookTextField(LastName));
            this.OneWayBind(ViewModel, vm => vm.FullName, v => v.FullName.StringValue);
 
            // ---- ビューモデル生成 ----
            ViewModel = new MainViewModel();
        }
    }

なお、このサンプルのビューモデルには「ReactiveUI/ViewModelを作る#WhenAny」にあるものを使っている。

関連項目[編集]

参考文献[編集]