C# 从SortedList中T.MyProperty上的所有属性更改事件获取IObservable<;MyClass>;
我有一个类,C# 从SortedList中T.MyProperty上的所有属性更改事件获取IObservable<;MyClass>;,c#,.net,system.reactive,C#,.net,System.reactive,我有一个类,MyClass,它实现了INotifyPropertyChanged,并且有一些属性实现了PropertyChanged。当MyClass.MyProperty更改时,PropertyChanged按预期激发。另一个类包含一个SortedList。我尝试将事件合并到包含SortedSet的类中的一个可观察对象中并订阅它,但它似乎从来没有任何事件。以下是我正在尝试的: Observable.Merge(MySortedList.ToObservable()) .Subscribe
MyClass
,它实现了INotifyPropertyChanged
,并且有一些属性实现了PropertyChanged
。当MyClass.MyProperty
更改时,PropertyChanged
按预期激发。另一个类包含一个SortedList
。我尝试将事件合并到包含SortedSet
的类中的一个可观察对象中并订阅它,但它似乎从来没有任何事件。以下是我正在尝试的:
Observable.Merge(MySortedList.ToObservable())
.Subscribe(evt => Console.WriteLine("{0} changed", evt.MyProperty));
我试图得到的是一个可观察的对象,它包含我的SortedList
中每个项目的所有事件。我尝试过使用ObservaleCollection,但这并没有改变任何东西,事实上也不会改变,因为当包含项的属性发生变化时,它不会触发collectionchanged。我可以监听SortedList
中的单个元素,并查看PropertyChanged事件激发,但我想要的是一个包含SortedList
中所有元素的所有PropertyChanged事件流的单个可观察对象
使用Rx似乎很容易做到这一点,但我似乎不知道如何做到。根据您的描述,假设您能够提供:
IEnumerable<KeyValuePair<string, IObservable<object>>> observableProperties;
我可以这样创建可观察属性
:
class MyClass
{
public IObservable<int> X { get { ... } }
public IObservable<string> S { get { ... } }
}
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>())
};
var myObject=new MyClass();
var observableProperties=new[]
{
新的KeyValuePair(“X”,myObject.X.Cast()),
新的KeyValuePair(“S”,myObject.S.Cast())
};
我为RxCookBook撰写了一篇关于这个主题的文章,你可以在这里找到
这里有关于PropertyChange通知的更多文章
它通过将可观测集合的更改汇总起来,解决了您需要的问题。通过使用ObservableCollection
,您还可以在集合中添加或删除项目时收到通知
如果您不想使用ObservableCollection
(即,您只想跟踪集合给定快照的属性),则需要执行其他操作。首先,我假设您有一个INoftifyPropertyChanged
到IObservable
扩展方法,或者您将使用标准事件到IObservable
方法
接下来,您可以将值列表投影到更改序列列表中,即IEnumerable
到IEnumerable
。这允许您使用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);
}
}
编辑我的问题以获得更清晰和更多信息。我认为您当前的答案不符合我的需要,因为我需要一个单一的可观察的,其中包含我的SortedList
上PropertyChanged
中的所有事件,其中每个
元素都是需要合并的事件流的源。您的答案似乎是在一个类的单个实例上组合来自多个属性的多个事件。我有一个SortedList
,需要来自所述列表中所有N个元素的事件的组合流。编译时元素的数量是未知的。这正是我想要做的。我对Rx还是有点陌生,经过几个小时的搜索,我找不到一个关于如何做这件事的参考。我肯定会看看你上面的链接,并把它们加入书签。再次感谢!有什么方法可以在嵌套属性上执行此操作?实际上我使用了Items.CollectionItemsChange(item=>item.Price).Subscribe(x=>{TotalPrice=Items.Sum(item=>item.Price);})
但是如果我尝试使用Items.CollectionItemsChange(item=>item.Detail.Price)中的嵌套属性,订阅(x=>{TotalPrice=Items.Sum=>item.Detail.Price);})
它不会得到通知。我是rx的新手,因此非常感谢您的帮助!是的,有,但要小心你的愿望。在您的第一个示例中,您已经有了一个非常低效的实现(考虑一下,如果我添加100项,它会做什么)。在第二个实现中,您需要跟踪项目的添加/删除/更新
、对每个项目的详细信息
属性的更改,然后在每次发生任何更改时内部订阅/取消订阅,然后监听价格
属性的更改。所以是可行的。然而,每次有人问我这个问题,我们发现实际上需要一个更好的设计,所以我从来没有写过。我相信IMPL是有用的
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