问题
Is it possible to create a ReactiveUI derived collection that has more elements in it than the original?
I've seen that there is a way of filtering a collection, and selecting single properties, but what I'm looking for is the equivalent of the SelectMany operation for enumerables.
To illustrate, imagine trying to get a derived collection representing every passenger stuck in a traffic jam.
class Car
{
ReactiveCollection<Passenger> Passengers;
}
var TrafficJam=new ReactiveCollection<Car>();
EveryPassengerInTheTrafficJam=Cars.CreateDerivedCollection(c=>c.Passengers);
The above doesn't work, I think the error was IEnumerable<ReactiveCollection<Passenger>>
can't be cast to ReactiveCollection<Passenger>
- or something up with the types, in any case.
I can't figure out the right approach for this flattening - admittedly I may be barking up completely the wrong tree here, so please let me know if there's a better way of achieving the same thing!
回答1:
At the moment, CreateDerivedCollection
doesn't support SelectMany
as a transformation, it gets too Tricky to handle removes. If you don't have many items, you can just regenerate the collection every time:
cars.Changed
.Select(_ => cars.SelectMany(x => x.Passengers).ToList())
.ToProperty(this, x => x.Passengers);
Edit: Alright, here we go:
var whenCarsOrPassengersInThoseCarsChange = Observable.Merge(
cars.Changed
.SelectMany(_ =>
cars.Select(x => x.Passengers.Changed).Merge())
.Select(_ => Unit.Default),
cars.Changed.Select(_ => Unit.Default));
whenCarsOrPassengersInThoseCarsChange.StartWith(Unit.Default)
.Select(_ => cars.SelectMany(x => x.Passengers).ToList())
.ToProperty(this, x => x.Passengers);
So, the idea is that we've got two main situations when we want to reevaluate the passengers list:
- When one of the passengers change in the cars
- When one of the cars change
However, the tricky part is, we only want to watch passengers for cars in the collection (i.e. if a car is removed, we no longer care about its passengers).
Properly tracking suicidal passengers
So, the idea in that weird SelectMany is, "Every time the car list changes, build a new list of Observables that represent when the passenger collection changes, and merge them all together".
However, if we only had that statement, we would have to wait for a car to be added and its passengers change before we got a new passenger list, so we also have to update when the list of cars change too.
What's this "Unit" business?
In this case, I actually don't care about the values that these Observables put out, just when they happen. "Unit" is the Rx version of void, it only has a single value, "Unit.Default". You use it when you only care when something happens, not what the value of it is.
回答2:
Hmm...I'm not all that familiar with ReactiveUI, but just reading thru, it looks like you need to alter where your SelectMany
goes:
var jam = cars.SelectMany(x => x.Passengers).CreateDerivedCollection(p => p);
来源:https://stackoverflow.com/questions/15254708/creating-a-reactiveui-derived-collection-with-more-elements-than-the-original