7

我有一个类,MyClass它实现INotifyPropertyChanged并具有一些实现PropertyChanged. MyClass.MyProperty更改时,按PropertyChanged预期触发。另一个类包含一个SortedList<MyClass>。我尝试将事件合并到包含SortedSet<MyClass>并订阅它的类中的单个可观察对象中,但它似乎没有任何事件。这是我正在尝试的:

Observable.Merge(MySortedList.ToObservable())
   .Subscribe(evt => Console.WriteLine("{0} changed", evt.MyProperty));

我想要得到的是一个单独的 observable,它包含我的SortedList<MyClass>. 我已经尝试使用 ObservableCollection 代替,但这并没有改变任何东西,实际上也不会被期望,因为当包含的项目的属性发生变化时它不会触发 collectionchanged ,无论如何。我可以监听单个元素SortedList<MyClass>并查看 PropertyChanged 事件触发,但我想要的是一个单独的 Observable,它包含来自SortedList<MyClass>.

使用 Rx 似乎应该很容易做到这一点,但我似乎无法弄清楚如何。

4

2 回答 2

10

我已经为 RxCookBook 制作了一篇关于这个主题的文章,你可以在这里找到 https://github.com/LeeCampbell/RxCookbook/blob/master/Model/CollectionChange.md 关于 PropertyChange 通知的更多文章在这里https://github。 com/LeeCampbell/RxCookbook/blob/master/Model/PropertyChange.md

它通过汇总来自ObservableCollection<T>. 通过使用 ,ObservableCollection<T>您还可以在从集合中添加或删除项目时收到通知。

如果您不想使用ObservableCollection<T>(即您只想跟踪集合的给定快照的属性),那么您将需要做其他事情。首先,我假设您有一个INoftifyPropertyChangedtoIObservable<T>扩展方法,或者您将使用标准事件 toIObservable<T>方法。

接下来,您可以将值列表投影到更改序列列表中,即IEnumerable<T>to 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
于 2013-09-12T17:09:13.863 回答
0

假设根据您的描述,您能够提供:

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>())
};
于 2013-09-12T01:19:09.007 回答