从 SortedList 中 T.MyProperty 上的所有属性更改事件中获取 IObservab

本文关键字:属性 IObservab 获取 事件 MyClass SortedList MyProperty | 更新日期: 2023-09-27 18:30:55

我有一个实现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 这应该是相当容易做到的,但我似乎不知道怎么做。

从 SortedList<MyClass> 中 T.MyProperty 上的所有属性更改事件中获取 IObservab

我已经为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>(即您只想跟踪集合的给定快照的属性),则需要执行其他操作。首先,我假设您有一个INoftifyPropertyChangedIObservable<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>())
};