多くの場合、MVVM で提示する最も簡単な方法IObservable<T>
は、以下のような従来のビューモデル オブジェクトを作成し、手動でオブザーバブルにサブスクライブすることです。サブスクリプションは.ObserveOn(SynchronizationContext.Current)
、UI スレッドですべての通知をディスパッチするために使用して実行する必要があります。次に、その時点で同期コンテキストが存在する必要があります ( SynchronizationContext.Current
is null before new Application().Run(mainWindow)
)。以下のサンプルを参照してください。
public class ViewModel : INotifyPropertyChanged
{
private int _property1;
public int Property1
{
get => _property1;
set
{
_property1 = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Property1)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
景色:
<Window x:Class="ConsoleApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBox Text="{Binding Property1}" />
</Window>
呼び出し元メソッド:
[STAThread]
static void Main()
{
var model = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1)).Take(10);
var viewModel = new ViewModel();
var mainWindow = new MainWindow
{
DataContext = viewModel
};
IDisposable subscription = null;
mainWindow.Loaded += (sender, e) =>
subscription = model
.ObserveOn(SynchronizationContext.Current) // Dispatch all the events in the UI thread
.Subscribe(item => viewModel.Property1 = item);
new Application().Run(mainWindow);
subscription?.Dispose();
}
アップデート
もう 1 つのオプションは、ReactiveUI.WPFとさらに簡潔なReactiveUI.Fodyを使用して、ビューモデルで自動プロパティを生成することです。
ビューモデル:
public class ViewModel : ReactiveObject, IDisposable
{
private readonly IDisposable subscription;
public ViewModel(IObservable<long> source)
{
subscription = source
.ObserveOnDispatcher()
.ToPropertyEx(this, x => x.Property1);
}
// To be weaved by Fody
public extern long Property1 { [ObservableAsProperty]get; }
// Unsubscribe from the source observable
public void Dispose() => subscription.Dispose();
}
ここでObserveOnDispatcher()
の呼び出しは、ディスパッチャーが開始されておらず、SynchronizationContext.Current
null の場合でも機能します。呼び出し元メソッド:
[STAThread]
static void Main()
{
new Application().Run(
new MainWindow
{
DataContext = new ViewModel(
Observable.Timer(
TimeSpan.Zero,
TimeSpan.FromSeconds(1))
.Take(20))
});
}
ソリューション ファイルの近くにある FodyWeavers.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
<ReactiveUI />
</Weavers>