Mvvm 使用ReactiveUI通过切换开关控制(启动/停止)IObservable

Mvvm 使用ReactiveUI通过切换开关控制(启动/停止)IObservable,mvvm,uwp,system.reactive,reactiveui,Mvvm,Uwp,System.reactive,Reactiveui,我正试图钩住一个流(IObservable),通过UWP项目中的ToggleSwitch进行控制。我希望在开关处于On状态时启动流媒体,在开关处于Off状态时停止流媒体 所以我们的想法是 1.创建两个命令,一个用于启动流,另一个用于停止流。 2.创建两个监视开关状态的观察对象,并在条件正确时调用命令 视图模型 public类MainPageViewModel:ViewModelBase { 公共反应命令流命令{get;} 公共反应命令StopCommand{get;} 公共IObservable

我正试图钩住一个流(
IObservable
),通过UWP项目中的
ToggleSwitch
进行控制。我希望在开关处于
On
状态时启动流媒体,在开关处于
Off
状态时停止流媒体

所以我们的想法是 1.创建两个命令,一个用于启动流,另一个用于停止流。 2.创建两个监视开关状态的观察对象,并在条件正确时调用命令

视图模型
public类MainPageViewModel:ViewModelBase
{
公共反应命令流命令{get;}
公共反应命令StopCommand{get;}
公共IObservable流{get;set;}
私人住宅;
公共图书馆
{
get=>\u isStreamOn;
set=>this.RaiseAndSetIfChanged(ref\u isStreamOn,value);
}
公共MainPageViewModel()
{
var stream=GetStream();
var canSwitchOn=this.WhenAnyValue(x=>x.IsStreamOn);
var canSwitchOff=this.whenyValue(x=>x.IsStreamOn,isOn=>isOn!=true);
FlowStream=StreamCommand=ReactiveCommand.CreateFromObservable(
() =>
{
stream.Start();
返回可观察的.FromEventPattern(
h=>stream.DataAvailable+=h,
h=>stream.DataAvailable-=h)
.SelectMany(e=>e.EventArgs.Data)
.选择(项目=>项目));
},可开启);
StopCommand=ReactiveCommand.Create(
() =>
{
stream.Stop();
IsStreamOn=假;
},可关机);
canSwitchOff.InvokeCommand(StopCommand);
canSwitchOn.InvokeCommand(StreamCommand);
}
}
看法
公共密封部分类主页面:第页,IViewFor
{
公共主页()
{
初始化组件();
NavigationCacheMode=Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
ViewModel=新的MainPageViewModel();
此.whenActivate(订阅=>
{
订阅(this.OneWayBind(this.ViewModel,
vm=>vm.StreamCommand,
v=>v.chart.SeriesCollection[0].Stream));//图表负责显示数据
订阅(this.Bind(this.ViewModel,
vm=>vm.IsStreamOn,
v=>v.streamToggle.IsOn);
});
}
对象IViewFor.ViewModel
{
获取{return ViewModel;}
设置{ViewModel=(MainPageViewModel)值;}
}
公共主页视图模型视图模型
{
获取{return(MainPageViewModel)GetValue(ViewModelProperty);}
set{SetValue(ViewModelProperty,value);}
}
公共静态只读从属属性ViewModelProperty=
DependencyProperty.Register(“ViewModel”、typeof(MainPageViewModel)、typeof(MainPageViewModel)、null);
}
但是,
InvokeCommand
失败,因为它需要reactiveCommand来执行bool,而不是
单元

知道我如何在满足某些条件时调用命令吗?

如果您想根据
IObservable-isstream
observed打开和关闭流(
IObservable-FlowStream
),则可以执行以下操作:

IObservable<(long, float)> outputStream =
    IsStreamOn
        .Select(flag => flag ? FlowStream : Observable.Never<(long, float)>())
        .Switch();
下面是一个简单的测试:

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>();

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

var canSwitchOn = this.WhenAnyValue(x => x.IsStreamOn).Select(_ => Unit.Default);
这将允许您不将bool传递给命令

哦,如果您想在正确的条件下触发命令,那么您可能需要在这个原因中使用where()子句

例如


也许我没有说清楚。我想知道如何发送启动和停止流的命令。我有流API
Start
Stop
来控制底层事件泵。@resp78-仍然不够清楚,因为我认为我已经做到了这一点。你能说得更清楚吗?@resp78-Oh,那么你想根据
IsStreamOn
生成的值发送
stream.Start()
stream.Stop()
调用吗?这相当简单。但是你真的应该发布
GetStream()
的完整代码,因为可能有一种更干净的方法来完成它,这就是我要建议的方法。@resp78-我在回答的末尾添加了一个建议。GetStream是一种普通的方法。有趣的是,当调用
Start
时,它开始使用args
StreamDataEventArgs
触发
DataAvailable
事件。我很快就会尝试你的建议。我看到一些人制作了一个扩展方法,比如IgnoreResult(),或者其他可以执行选择的方法(=>Unit.Default>在IOBServable上这只在第一次工作。虽然当我切换开关时,在select运算符中有一个断点,断点确实被击中。不确定为什么它没有第二次调用命令。有两种可能,一种是CanExecute observable。在这种情况下,您可能不希望CanExecute,第二种可能是Stream.Start()仍在执行,Stream.Stop()检查命令的IsExecuting属性以查看。特别是如果使用我建议的方法。Where()语句检查bool的值以将其拆分为两个可观察值,则不需要canExecute。
IObservable<(long, float)> outputStream =
    FlowStream
        .Publish(fs =>
            IsStreamOn
                .Select(flag => flag ? fs : Observable.Never<(long, float)>())
                .Switch());
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>();
0 1 5 6 7
IObservable<(long, float)> outputStream =
    Observable
        .Create<(long, float)>(o =>
        {
            var stream = GetStream();
            return 
                FlowStream
                    .Publish(fs =>
                        IsStreamOn
                            .Do(flag => { if (flag) stream.Start(); else stream.Stop(); })
                            .Select(flag => flag ? fs : Observable.Never<(long, float)>())
                            .Switch())
                    .Subscribe(o);
        });
var canSwitchOn = this.WhenAnyValue(x => x.IsStreamOn).Select(_ => Unit.Default);
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);