我正在使用observe package。
考虑这个例子:
class Product extends Object with ChangeNotifier {
double _price = 0.0;
@reflectable double get price => _price;
@reflectable void set price(double value) {
if (value == null) throw new ArgumentError();
_price = notifyPropertyChange(#price, price, value);
}
}
class Order extends Object with ChangeNotifier {
final ObservableList<Product> products = new ObservableList<Product>();
double get total {
double sum = 0.0;
for (var item in products) {
sum += item.price;
}
return sum;
}
}
// Synchronizes the view total with the order total.
// Or rather, I'd like it to do that.
var order = new Order();
order.changes.listen((records) {
view.total = order.total;
});
如何重写此示例以使其正常工作?
我希望收到对象状态的任何更改的通知,即使这些更改发生在列表或列表中的项目中。
我是否必须管理所有项目和列表本身的更改订阅? Order
课程的内部或外部?通过哪个属性我会通知变更?无论如何,它似乎都很混乱。
答案 0 :(得分:2)
ObservableList
中的元素不会将通知传播到包含它们的列表。他们不能,因为他们没有参考列表。
此外,列表不会将通知转发给它所引用的类。
不是很满意,但我能想出的最好。
import 'dart:async' as async;
import 'package:observe/observe.dart';
class Product extends Object with ChangeNotifier {
double _price = 0.0;
@reflectable double get price => _price;
@reflectable void set price(double value) {
if (value == null) throw new ArgumentError();
_price = notifyPropertyChange(#price, price, value);
}
@override
String toString() => 'Product - price: $price';
}
class Order extends Object with ChangeNotifier {
final ObservableList<Product> products = new ObservableList<Product>();
// keep listeners to be able to cancel them
final List<async.StreamSubscription> subscriptions = [];
Order() {
products.changes.listen((cr) {
// only react to length changes (isEmpty, isNotempty changes are redundant)
var lengthChanges = cr.where((c) => c.name == #length);
if(lengthChanges.isNotEmpty) {
lengthChanges.forEach((lc) =>
notifyChange(lc));
// we can't know if only additions/removals were done therefore we
// cancel all existing listeners and set up new ones for all items
// after each length change
_updateProductsListeners();
}
});
// initial setup
_updateProductsListeners();
}
// cancel all product change listeners and create new ones
void _updateProductsListeners() {
print('updateListeners');
subscriptions.forEach((s) => s.cancel());
subscriptions.clear();
products.forEach((p)
=> subscriptions.add(p.changes.listen((crs) =>
crs.forEach((cr) =>
notifyPropertyChange(cr.name, cr.oldValue, cr.newValue)))));
}
double get total {
double sum = 0.0;
for (var item in products) {
sum += item.price;
}
return sum;
}
}
void main() {
// Synchronizes the view total with the order total.
// Or rather, I'd like it to do that.
var order = new Order();
order.changes.listen((records) {
//view.total = order.total;
records.forEach(print);
});
// a PathObserver example but it doesn't seem to be more convenient
var op = new PathObserver(order, 'products[3].price')..open((c) =>
print(c));
var prods = [new Product()..price = 1.0, new Product()..price = 2.0, new Product()..price = 3.0, new Product()..price= 4.0];
var prods2 = [new Product()..price = 5.0, new Product()..price = 6.0];
order.products.addAll(prods);
// use Future to allow change notification propagate between changes
new async.Future(() =>
order.products..addAll(prods2)..removeWhere((p) => p.price < 3.0))
.then((_) => new async.Future(() => order.products[3].price = 7.0));
new async.Future.delayed(new Duration(seconds: 1), () => print('done'));
}
我建议使用类似事件总线的东西,其中想要/应该通知事物的对象只是发送,事件和对某事感兴趣的对象在不知道其他对象存在的情况下监听。< / p>
答案 1 :(得分:0)
另一种解决方案是使用ListPathObserver。该类已弃用,但您可以复制其代码并重复使用它。通过该类,您可以监听所包含项目中的特定更改。要监视的字段由路径指定。