使用ReactiveUI通过ToggleSwitch控制(启动/停止)IObservable

时间:2017-09-25 06:11:02

标签: mvvm uwp system.reactive reactiveui

我正在尝试通过UWP项目中的IObservable挂钩流(ToggleSwitch)。期望是当交换机处于On状态时我开始流式传输,当它处于Off状态时停止。

所以想到的是 1.创建两个命令,一个用于启动流,另一个用于停止流。 2.创建两个监视开关状态的Observable,并在条件合适时InvokeCommand

视图模型

public class MainPageViewModel : ViewModelBase
{
    public ReactiveCommand<Unit, (long, float)> StreamCommand { get; }
    public ReactiveCommand<Unit, Unit> StopCommand { get; }
    public IObservable<(long, float)> FlowStream { get; set; }

    private bool _isStreamOn;

    public bool IsStreamOn
    {
        get => _isStreamOn;
        set => this.RaiseAndSetIfChanged(ref _isStreamOn, value);
    }

    public MainPageViewModel()
    {
        var stream = GetStream();

        var canSwitchOn = this.WhenAnyValue(x => x.IsStreamOn);
        var canSwitchOff = this.WhenAnyValue(x => x.IsStreamOn, isOn => isOn != true);

        FlowStream = StreamCommand = ReactiveCommand.CreateFromObservable(
            () =>
                {
                    stream.Start();
                    return Observable.FromEventPattern<StreamDataEventArgs<(long, INumeric, INumeric, INumeric)>>(
                            h => stream.DataAvailable += h,
                            h => stream.DataAvailable -= h)
                        .SelectMany(e => e.EventArgs.Data)
                        .Select(item => item));
                }, canSwitchOn);

        StopCommand = ReactiveCommand.Create(
            () =>
            {
                stream.Stop();
                IsStreamOn = false;
            }, canSwitchOff);

        canSwitchOff.InvokeCommand(StopCommand);
        canSwitchOn.InvokeCommand(StreamCommand);
    }

}

视图

public sealed partial class MainPage : Page, IViewFor<MainPageViewModel>
{
    public MainPage()
    {
        InitializeComponent();
        NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
        ViewModel = new MainPageViewModel();

        this.WhenActivated(subscription =>
        {
            subscription(this.OneWayBind(this.ViewModel,
                vm => vm.StreamCommand,
                v => v.chart.SeriesCollection[0].Stream)); // Chart take care of displaying data

            subscription(this.Bind(this.ViewModel,
                vm => vm.IsStreamOn,
                v => v.streamToggle.IsOn));
        });
    }

    object IViewFor.ViewModel
    {
        get { return ViewModel; }
        set { ViewModel = (MainPageViewModel)value; }
    }

    public MainPageViewModel ViewModel
    {
        get { return (MainPageViewModel)GetValue(ViewModelProperty); }
        set { SetValue(ViewModelProperty, value); }
    }

    public static readonly DependencyProperty ViewModelProperty =
        DependencyProperty.Register("ViewModel", typeof(MainPageViewModel), typeof(MainPage), null);
}

但是,InvokeCommand失败,因为它需要ReactiveCommands取bool而不是Unit。 知道如何在满足某些条件时调用命令吗?

2 个答案:

答案 0 :(得分:2)

如果您想根据TImage观察点打开和关闭流(IObservable<(long, float)> FlowStream),那么您可以这样做:

IObservable<bool> IsStreamOn

因此,每次IObservable<(long, float)> outputStream = IsStreamOn .Select(flag => flag ? FlowStream : Observable.Never<(long, float)>()) .Switch(); 生成IsStreamOn时,您都会开始从true获取值,否则值会停止。

这假设FlowStream很热。如果没有,请执行以下操作:

FlowStream

这是一个简单的测试:

IObservable<(long, float)> outputStream =
    FlowStream
        .Publish(fs =>
            IsStreamOn
                .Select(flag => flag ? fs : Observable.Never<(long, float)>())
                .Switch());

这会产生:

0
1
5
6
7

鉴于评论实际上正在调用void Main() { IObservable<long> outputStream = FlowStream .Publish(fs => IsStreamOn .Select(flag => flag ? fs : Observable.Never<long>()) .Switch()); using (outputStream.Subscribe(Console.WriteLine)) { IsStreamOn.OnNext(true); Thread.Sleep(TimeSpan.FromSeconds(2.5)); IsStreamOn.OnNext(false); Thread.Sleep(TimeSpan.FromSeconds(3.0)); IsStreamOn.OnNext(true); Thread.Sleep(TimeSpan.FromSeconds(3.0)); } } IObservable<long> FlowStream = Observable.Interval(TimeSpan.FromSeconds(1.0)); Subject<bool> IsStreamOn = new Subject<bool>(); .Start(),请尝试这样的事情:

.Stop()

答案 1 :(得分:1)

在这些使用你的观察者的场景中我倾向于

var canSwitchOn = this.WhenAnyValue(x => x.IsStreamOn).Select(_ => Unit.Default);

这将允许您不要将bool传递给命令。

如果你想在正确的条件下触发命令,你也可能想要这个原因中的where()子句。

例如

var switchOn = this.WhenAnyValue(x => x.IsStreamOn).Where(x => x).Select(_ => Unit.Default);
var switchOff = this.WhenAnyValue(x => x.IsStreamOn).Where(x => !x).Select(_ => Unit.Default);