观察项目被添加到 RX 中的列表
Observing items being added to a list in RX
我正在尝试运行一个简单的演示。
我有一个字符串集合,我想在不使用任何控制事件代码的情况下观察它的添加。不知何故,我的印象可能是错误的,即 Rx 或 .Net 的另一部分支持这一点,而无需诉诸连接所有(可能或不可能)将成员添加到集合中的各种事件。
如果我用一个间隔替换我的 source
,就像在注释掉的代码中一样,委托将被调用(ala,var source = Observable.Interval(TimeSpan.FromSeconds(1));
。这让我希望我可以在这里做我想做的事,也许是错误的。
基本示例来自Creating and Subscribing to Simple Observable Sequences
在下面的代码中,我想要做的是直接观察 source
集合(而不是通过控制事件)并在将项目添加到集合时调用委托。
我宁愿不绕过 LINQ 或 RX,如果它们确实支持我的论点,即它们支持此功能。
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading;
public class frmRx
{
ObservableCollection<string> ObservableCollection = new ObservableCollection<string>();
Dim source = Observable.ToObservable(ObservableCollection).ObserveOn(SynchronizationContext.Current)
//this code worked, but it's not a collection I made
//source = Observable.Interval(TimeSpan.FromSeconds(1)).Select(x => x.ToString).ObserveOn(SynchronizationContext.Current);
private void frmRx_Load(System.Object sender, System.EventArgs e)
{
IConnectableObservable<string> Publication = Observable.Publish<string>(source);
Publication.Subscribe(x => { AddToTreeView(x); }, ex => { }, () => { });
Publication.Connect();
}
private void AddToTreeView(string Text)
{
TreeView1.Nodes.Add(Text); //this never gets called
}
// this is just my test way of adding a member to the collection.
// but the adding could happen anywhere,
// and I want to watch the collection changes regardless of how it came about
private void TextBox1_TextChanged(System.Object sender, System.EventArgs e)
{
ObservableCollection.Add(TextBox1.Text.Last);
}
public frmRx()
{
Load += frmRx_Load;
TextBox1.TextChanged += TextBox1_TextChanged;
}
}
您犯了一个错误,即 Observable.ToObservable(ObservableCollection)
将创建一个 IObservable<string>
,该 IObservable<string>
将为 ObservableCollection
的未来更新生成值。
没有。
.ToObservable(...)
扩展方法简单地将 IEnumerable<>
转换为 IObservable<>
,以便在订阅可观察对象的时刻枚举值。
如果您希望将新值推送给订阅者,则需要使用 Subject<string>
。
除此之外,您的代码并不尽可能简单。你为什么要发布 observables?
这里是你可以编写的最简单的代码来让它工作:
public class frmRx
{
private Subject<string> source = new Subject<string>();
public frmRx()
{
source.ObserveOn(this).Subscribe(x => TreeView1.Nodes.Add(x));
TextBox1.TextChanged += (s, e) => source.OnNext(TextBox1.Text);
}
}
我添加了 .ObserveOn(this)
,因为这是一个好习惯,但在这种情况下不需要。
不过我更希望看到的是:
public class frmRx
{
public frmRx()
{
Observable
.FromEventPattern(
h => textBox1.TextChanged += h,
h => textBox1.TextChanged -= h)
.Select(x => textBox1.Text)
.Subscribe(x => treeView1.Nodes.Add(x));
}
}
这避免了主题,并且在强类型化的情况下尽可能简单。
最好更进一步,在关闭时更好地清理您的订阅,如下所示:
var subscription =
Observable
.FromEventPattern(
h => textBox1.TextChanged += h,
h => textBox1.TextChanged -= h)
.Select(x => textBox1.Text)
.Subscribe(x => treeView1.Nodes.Add(x));
this.FormClosing += (s, e) => subscription.Dispose();
最简单的方法是使用 Rx.net 框架,例如 ReactiveUI。我将向您展示它是如何工作的。
ReactiveList<string> _collection = new ReactiveList<string>();
public Constructor()
{
var subscription = _collection.ItemsAdded.Subject(added => doSomething(added));
this.Disposed += (o, e) => subscription.Dispose();
}
这里需要多少代码才能在没有第三方的情况下"work"。此外,这段代码根本没有异常处理。
public class ViewModel
{
private ObservableCollection<string> _source = new ObservableCollection<string>();
public ViewModel()
{
//There will be issues with the exception handling
Observable.FromEventPattern
<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>
(x => _source.CollectionChanged += x, x => _source.CollectionChanged -= x)
.Where(x => x.EventArgs.Action == NotifyCollectionChangedAction.Add)
.SelectMany(x => x.EventArgs.NewItems.Cast<string>())
.Subscribe(AddToTreeView);
}
public void AddToTreeView(string text)
{
TreeView1.Nodes.Add(text);
}
}
我正在尝试运行一个简单的演示。
我有一个字符串集合,我想在不使用任何控制事件代码的情况下观察它的添加。不知何故,我的印象可能是错误的,即 Rx 或 .Net 的另一部分支持这一点,而无需诉诸连接所有(可能或不可能)将成员添加到集合中的各种事件。
如果我用一个间隔替换我的 source
,就像在注释掉的代码中一样,委托将被调用(ala,var source = Observable.Interval(TimeSpan.FromSeconds(1));
。这让我希望我可以在这里做我想做的事,也许是错误的。
基本示例来自Creating and Subscribing to Simple Observable Sequences
在下面的代码中,我想要做的是直接观察 source
集合(而不是通过控制事件)并在将项目添加到集合时调用委托。
我宁愿不绕过 LINQ 或 RX,如果它们确实支持我的论点,即它们支持此功能。
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading;
public class frmRx
{
ObservableCollection<string> ObservableCollection = new ObservableCollection<string>();
Dim source = Observable.ToObservable(ObservableCollection).ObserveOn(SynchronizationContext.Current)
//this code worked, but it's not a collection I made
//source = Observable.Interval(TimeSpan.FromSeconds(1)).Select(x => x.ToString).ObserveOn(SynchronizationContext.Current);
private void frmRx_Load(System.Object sender, System.EventArgs e)
{
IConnectableObservable<string> Publication = Observable.Publish<string>(source);
Publication.Subscribe(x => { AddToTreeView(x); }, ex => { }, () => { });
Publication.Connect();
}
private void AddToTreeView(string Text)
{
TreeView1.Nodes.Add(Text); //this never gets called
}
// this is just my test way of adding a member to the collection.
// but the adding could happen anywhere,
// and I want to watch the collection changes regardless of how it came about
private void TextBox1_TextChanged(System.Object sender, System.EventArgs e)
{
ObservableCollection.Add(TextBox1.Text.Last);
}
public frmRx()
{
Load += frmRx_Load;
TextBox1.TextChanged += TextBox1_TextChanged;
}
}
您犯了一个错误,即 Observable.ToObservable(ObservableCollection)
将创建一个 IObservable<string>
,该 IObservable<string>
将为 ObservableCollection
的未来更新生成值。
没有。
.ToObservable(...)
扩展方法简单地将 IEnumerable<>
转换为 IObservable<>
,以便在订阅可观察对象的时刻枚举值。
如果您希望将新值推送给订阅者,则需要使用 Subject<string>
。
除此之外,您的代码并不尽可能简单。你为什么要发布 observables?
这里是你可以编写的最简单的代码来让它工作:
public class frmRx
{
private Subject<string> source = new Subject<string>();
public frmRx()
{
source.ObserveOn(this).Subscribe(x => TreeView1.Nodes.Add(x));
TextBox1.TextChanged += (s, e) => source.OnNext(TextBox1.Text);
}
}
我添加了 .ObserveOn(this)
,因为这是一个好习惯,但在这种情况下不需要。
不过我更希望看到的是:
public class frmRx
{
public frmRx()
{
Observable
.FromEventPattern(
h => textBox1.TextChanged += h,
h => textBox1.TextChanged -= h)
.Select(x => textBox1.Text)
.Subscribe(x => treeView1.Nodes.Add(x));
}
}
这避免了主题,并且在强类型化的情况下尽可能简单。
最好更进一步,在关闭时更好地清理您的订阅,如下所示:
var subscription =
Observable
.FromEventPattern(
h => textBox1.TextChanged += h,
h => textBox1.TextChanged -= h)
.Select(x => textBox1.Text)
.Subscribe(x => treeView1.Nodes.Add(x));
this.FormClosing += (s, e) => subscription.Dispose();
最简单的方法是使用 Rx.net 框架,例如 ReactiveUI。我将向您展示它是如何工作的。
ReactiveList<string> _collection = new ReactiveList<string>();
public Constructor()
{
var subscription = _collection.ItemsAdded.Subject(added => doSomething(added));
this.Disposed += (o, e) => subscription.Dispose();
}
这里需要多少代码才能在没有第三方的情况下"work"。此外,这段代码根本没有异常处理。
public class ViewModel
{
private ObservableCollection<string> _source = new ObservableCollection<string>();
public ViewModel()
{
//There will be issues with the exception handling
Observable.FromEventPattern
<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>
(x => _source.CollectionChanged += x, x => _source.CollectionChanged -= x)
.Where(x => x.EventArgs.Action == NotifyCollectionChangedAction.Add)
.SelectMany(x => x.EventArgs.NewItems.Cast<string>())
.Subscribe(AddToTreeView);
}
public void AddToTreeView(string text)
{
TreeView1.Nodes.Add(text);
}
}