2012-05-15 24 views
1

我有一個ObservableCollection<Data> Items如何使用Linq或擴展方法來滿足CanExecute上的這個條件?

數據有一個「列」屬性,它又是一個ObservableCollection<Column>

Column對象具有名爲「IsActive」的布爾屬性。

我有一個情況,我需要確定是否所有「項目」都具有「列」屬性,如果是這樣,所有列應該或者「IsActive」爲true或false,但不是兩者。

訣竅是我需要把這個邏輯放在一個按鈕的CanExecute中..我需要使這個儘可能高效和快速......任何想法? 的結構是:

public class MyClass 
{ 
    public ObservableCollection<Data> Items 
    { 
     get{return _items;} 
    } 
} 

public class Data 
{ 
    public ObservableCollection<Column> Columns 
    { 
     get{return _columns;} 
    } 
} 

public class Column 
{ 

    public bool IsActive{ get; set;} 

} 

謝謝!

+0

顯示'Data'和'Column'的一些結構 –

+0

「我聽說canexecute持續不斷地發生火災」誰說的,在哪裏? –

+0

我添加了結構,它是我所擁有的樣本 – user1202434

回答

2

這聽起來像不成熟的優化。你是否測量過簡單化方法的速度?通過一些不太大的集合來迭代現代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實例設置更改通知處理程序來完成此操作。它有點乏味,因爲你有兩個級別的集合,但它將確保每當向集合中添加或刪除ColumnIsActive屬性發生更改時,更新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集合。

+0

Brilliant,按預期工作。謝謝你真的很好的答案。如果可以的話,我會贊成兩次。 – user1202434