我有一个实现INotifyPropertyChanged
的类,MyClass
,并具有一些实现PropertyChanged
的属性。 当MyClass.MyProperty
发生变化时,PropertyChanged
会按预期触发。 另一个类包含一个SortedList<MyClass>
。我尝试将这些事件合并到包含SortedSet<MyClass>
的类中的单个可观察对象中并订阅它,但它似乎没有任何事件。 这是我正在尝试的:
Observable.Merge(MySortedList.ToObservable())
.Subscribe(evt => Console.WriteLine("{0} changed", evt.MyProperty));
我试图得到的是一个单一的可观察量,其中包含我SortedList<MyClass>
中每个项目的所有事件。 我尝试使用 ObservableCollection,但这不会改变任何东西,也不会改变,因为无论如何,当包含项的属性更改时,它不会触发 collectionchange。 我可以侦听SortedList<MyClass>
中的各个元素并看到 PropertyChanged 事件触发,但我想要的是一个可观察的,其中包含来自SortedList<MyClass>
中所有元素的所有 PropertyChanged 事件的流。
似乎使用 Rx 这应该是相当容易做到的,但我似乎不知道怎么做。
我已经为RxCookBook撰写了一篇关于这个主题的文章,你可以在这里找到https://github.com/LeeCampbell/RxCookbook/blob/master/Model/CollectionChange.md有关财产更改通知的更多文章在这里 https://github.com/LeeCampbell/RxCookbook/blob/master/Model/PropertyChange.md
它通过聚合ObservableCollection<T>
的更改来解决您需要的内容。通过使用ObservableCollection<T>
,您还可以在集合中添加或删除项目时收到通知。
如果您不想使用该ObservableCollection<T>
(即您只想跟踪集合的给定快照的属性),则需要执行其他操作。首先,我假设您有一个INoftifyPropertyChanged
来IObservable<T>
扩展方法,或者您只是要使用标准事件来IObservable<T>
方法。
接下来,您可以将值列表投影到更改序列列表中,即 IEnumerable<T>
IEumerable<IObserable<T>>
.这允许您使用Observable.Merge
将更改列表平展为单个更改流。
如果您不想使用上面的链接,下面是一个示例:
void Main()
{
var myList = new List<MyThing>{
new MyThing{Name="Lee", Age=31},
new MyThing{Name="Dave", Age=37},
new MyThing{Name="Erik", Age=44},
new MyThing{Name="Bart", Age=24},
new MyThing{Name="James", Age=32},
};
var subscription = Observable.Merge(myList.Select(t=>t.OnAnyPropertyChanges()))
.Subscribe(x=>Console.WriteLine("{0} is {1}", x.Name, x.Age));
myList[0].Age = 33;
myList[3].Name = "Bob";
subscription.Dispose();
}
// Define other methods and classes here
public class MyThing : INotifyPropertyChanged
{
private string _name;
private int _age;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public int Age
{
get { return _age; }
set
{
_age = value;
OnPropertyChanged("Age");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public static class NotificationExtensions
{
/// <summary>
/// Returns an observable sequence of the source any time the <c>PropertyChanged</c> event is raised.
/// </summary>
/// <typeparam name="T">The type of the source object. Type must implement <seealso cref="INotifyPropertyChanged"/>.</typeparam>
/// <param name="source">The object to observe property changes on.</param>
/// <returns>Returns an observable sequence of the value of the source when ever the <c>PropertyChanged</c> event is raised.</returns>
public static IObservable<T> OnAnyPropertyChanges<T>(this T source)
where T : INotifyPropertyChanged
{
return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
handler => handler.Invoke,
h => source.PropertyChanged += h,
h => source.PropertyChanged -= h)
.Select(_=>source);
}
}
这将输出:
Lee is 33
Bob is 24
假设从您的描述中您能够提供以下内容:
IEnumerable<KeyValuePair<string, IObservable<object>>> observableProperties;
您可以使用它将属性可观察量合并为单个可观察量:
IObservable<KeyValuePair<string, object>> changes = observableProperties
.Select(p => p.Value
.Select(o => new KeyValuePair<string, object>(p.Key, o)))
.Merge();
如果您发现这还不够,则需要提供有关无法提供observableProperties
的原因的更多详细信息。
例如,如果我有这样的类:
class MyClass
{
public IObservable<int> X { get { ... } }
public IObservable<string> S { get { ... } }
}
我可以创建这样的observableProperties
:
var myObject = new MyClass();
var observableProperties = new []
{
new KeyValuePair<string, IObservable<object>>("X", myObject.X.Cast<object>()),
new KeyValuePair<string, IObservable<object>>("S", myObject.S.Cast<object>())
};