這聽起來像不成熟的優化。你是否測量過簡單化方法的速度?通過一些不太大的集合來迭代現代CPU只需要幾毫秒。
如果要使用LINQ計算所有Column
對象是處於活動狀態還是非活動狀態,則可以使用此表達式。
public Boolean CanExecute {
get {
var aggregate = Items
.SelectMany(i => i.Columns)
.Aggregate(
new {
IsEmpty = true,
AllAreActive = true,
AllAreInactive = true
},
(a, c) => new {
IsEmpty = false,
AllAreActive = a.AllAreActive && c.IsActive,
AllAreInactive = a.AllAreInactive && !c.IsActive
}
);
return !aggregate.IsEmpty && (aggregate.AllAreActive || aggregate.AllAreInactive);
}
此代碼將遍歷所有集合中的所有元素。您可以通過使用for
循環來改進此問題,並在兩個布爾變量都變爲false時將其分解。這也可以通過在LINQ中使用TakeWhile
使用帶有副作用的謂詞完成,但簡單的for
循環可能更易於理解。
如果您認爲簡單的方法太慢,您需要跟蹤CanExecute
屬性MyClass
級別。您可以通過爲所有ObservableCollection
實例設置更改通知處理程序來完成此操作。它有點乏味,因爲你有兩個級別的集合,但它將確保每當向集合中添加或刪除Column
或IsActive
屬性發生更改時,更新MyClass
中支持CanExecute
的布爾變量。
最初Column
必須實現INotifyPropertyChanged
:
class Column : INotifyPropertyChanged {
Boolean isActive;
public Boolean IsActive {
get { return this.isActive; }
set {
if (this.isActive == value)
return;
this.isActive = value;
OnPropertyChanged("IsActive");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(String propertyName) {
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Data
有揭露這對於缺乏更好的名稱我已經叫AllColumnsAreActiveOrInactive
和這個屬性的變化是通過實現INotifyPropertyChanged
信號所需的性能。
要跟蹤所有列的狀態,需要處理Column
集合的CollectionChanged
。當添加新的Column
時,可以重新計算AllColumnsAreActiveOrInactive
的值,而無需重複收集Column
集合。但是,IsActive
在單個Column
上更改或當Column
被刪除時,必須迭代該集合以確定AllColumnsAreActiveOrInactive
的新值。
class Data : INotifyPropertyChanged {
readonly ObservableCollection<Column> columns;
Boolean allColumnsAreActive = true;
Boolean allColumnsAreInactive = true;
Boolean allColumnsAreActiveOrInactive = false;
public Data() {
this.columns = new ObservableCollection<Column>();
this.columns.CollectionChanged += CollectionChanged;
}
public ObservableCollection<Column> Columns { get { return this.columns; } }
public Boolean AllColumnsAreActiveOrInactive {
get { return this.allColumnsAreActiveOrInactive; }
set {
if (value == this.allColumnsAreActiveOrInactive)
return;
this.allColumnsAreActiveOrInactive = value;
OnPropertyChanged("AllColumnsAreActiveOrInactive");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(String propertyName) {
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
void CollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) {
if (e.Action == NotifyCollectionChangedAction.Reset) {
RecomputeAllColumnsAreActiveOrInactive();
return;
}
if (e.OldItems != null) {
foreach (var item in e.OldItems.Cast<Column>())
item.PropertyChanged -= ColumnPropertyChanged;
RecomputeAllColumnsAreActiveOrInactive();
return;
}
if (e.NewItems != null) {
foreach (var column in e.NewItems.Cast<Column>()) {
column.PropertyChanged += ColumnPropertyChanged;
this.allColumnsAreActive = this.allColumnsAreActive && column.IsActive;
this.allColumnsAreInactive = this.allColumnsAreInactive && !column.IsActive;
}
UpdateAllColumnsAreActiveOrInactive();
}
}
void ColumnPropertyChanged(Object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == "IsActive") {
var column = sender as Column;
RecomputeAllColumnsAreActiveOrInactive();
}
}
void RecomputeAllColumnsAreActiveOrInactive() {
this.allColumnsAreActive = this.columns.All(c => c.IsActive);
this.allColumnsAreInactive = this.columns.All(c => !c.IsActive);
UpdateAllColumnsAreActiveOrInactive();
}
void UpdateAllColumnsAreActiveOrInactive() {
AllColumnsAreActiveOrInactive = this.columns.Any()
&& (this.allColumnsAreActive || this.allColumnsAreInactive);
}
}
class Column : INotifyPropertyChanged {
Boolean isActive;
public Boolean IsActive {
get { return this.isActive; }
set {
if (this.isActive == value)
return;
this.isActive = value;
OnPropertyChanged("IsActive");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(String propertyName) {
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
要完成此解決方案Column/Data
徵收方式有重複,爲Data/MyClass
集合。
顯示'Data'和'Column'的一些結構 –
「我聽說canexecute持續不斷地發生火災」誰說的,在哪裏? –
我添加了結構,它是我所擁有的樣本 – user1202434