SelectMany触发订阅,而选择不
在下面的示例中,我不明白为什么选择在SelectMany时不会触发订阅。这个示例是基于我正在研究的事情,但缩短为简单,使问题可再现。
当我点击按钮时,_subject.onnext
被调用。 ViewModel订阅_subject
和调用getObservable()
,它返回iobservable< unit>
。此时,debug.writeline(“订阅”);
未在getObservable()
中击中。
但是,如果我更改_subject.Select(_ => getObServable())。subsibribre();
_subject.SelectMany(_ => getObservable())。
调试线被击中。
订阅如何使用SelectMany而不是选择?我的理解是,使用可观察到的。创建,在订阅时,指定的代表将被执行。我只是看不到SelectMany在哪里进行订阅。
查看:
<Window x:Class="Rxtest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Rxtest"
d:DataContext="{d:DesignInstance Type=viewModels:ViewModel}"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button Command="{Binding SaveCommand}"/>
</Grid>
</Window>
背后的代码:
using System.Windows;
namespace Rxtest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
}
ViewModel:
using System;
using System.Diagnostics;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows.Input;
namespace Rxtest
{
public class ViewModel
{
private ICommand _saveCommand;
private Subject<int> _subject = new Subject<int>();
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(
p => true,
p => DoSomeImportantMethod());
}
return _saveCommand;
}
}
public ViewModel()
{
_subject.Select(_ => GetObservable()).Subscribe();
}
private void DoSomeImportantMethod()
{
_subject.OnNext(1);
}
private IObservable<Unit> GetObservable()
{
return Observable.Create<Unit>(observer =>
{
observer.OnNext(Unit.Default);
Debug.WriteLine("SUBSCRIBED");
return Disposable.Empty;
});
}
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
_canExecute = canExecute;
_execute = execute;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
}
I do not understand in the example below why Select does not trigger the subscription while SelectMany does. This example is based off of something I am working on but reduced to as simple as I can get it so that the issue is reproducible.
When I hit the button, _subject.OnNext
is called. The ViewModel is subscribed to _subject
and calls GetObservable()
which returns an IObservable<Unit>
. At this point Debug.WriteLine("SUBSCRIBED");
is not hit in GetObservable()
.
However, if I change _subject.Select(_ => GetObservable()).Subscribe();
to _subject.SelectMany(_ => GetObservable()).Subscribe();
the debug line is hit.
How is the subscription happening with SelectMany and not with Select? My understanding is that with Observable.Create, the specified delegate will be executed anytime a subscription is made. I just don't see where the subscription is being made with SelectMany.
View:
<Window x:Class="Rxtest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Rxtest"
d:DataContext="{d:DesignInstance Type=viewModels:ViewModel}"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Button Command="{Binding SaveCommand}"/>
</Grid>
</Window>
Code behind:
using System.Windows;
namespace Rxtest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
}
ViewModel:
using System;
using System.Diagnostics;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows.Input;
namespace Rxtest
{
public class ViewModel
{
private ICommand _saveCommand;
private Subject<int> _subject = new Subject<int>();
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(
p => true,
p => DoSomeImportantMethod());
}
return _saveCommand;
}
}
public ViewModel()
{
_subject.Select(_ => GetObservable()).Subscribe();
}
private void DoSomeImportantMethod()
{
_subject.OnNext(1);
}
private IObservable<Unit> GetObservable()
{
return Observable.Create<Unit>(observer =>
{
observer.OnNext(Unit.Default);
Debug.WriteLine("SUBSCRIBED");
return Disposable.Empty;
});
}
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
_canExecute = canExecute;
_execute = execute;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
全部都在打字中。
.select
在这里返回双重观察,iObservable&lt; iobservable&lt; unit&gt;&gt;
。订阅呼叫订阅可观察到的外部,但您的调试语句仅存在于内部观察处。内部可观察的仍然没有订阅。.selectmany
将双重观察的可观察到一个简单的iObservable&lt; unit&gt;
在其中您的调试语句将发射。It’s all in the typing.
.Select
here is returning a double observable,IObservable<IObservable<Unit>>
. The subscribe call subscribes to the outer observable, but your Debug statement only exists on the inner observable. The inner observable remains unsubscribed to..SelectMany
flattens the double observable into a simpleIObservable<Unit>
where your Debug statement will fire.