2010-09-29 27 views
7

Tôi đã sử dụng ObservableCollection với WPF để gắn kết và hoạt động tốt. Những gì tôi thực sự muốn tại thời điểm này là một từ điển như một, mà có một chìa khóa mà tôi có thể sử dụng, vì vậy có hiệu quả như "ObservableCollection".WPF - Làm cách nào để tôi có thể triển khai ObservableCollection <K,T> bằng khóa (như từ điển)?

Bạn có thể đề xuất mã có thể được sử dụng để cung cấp ObservableCollection như vậy không? Mục tiêu là có một cấu trúc giống như từ điển mà tôi có thể liên kết từ WPF.

Cảm ơn

Trả lời

1

Tạo một lớp mà thực hiện các IDictionary, INotifyCollectionChanged & giao diện INotifyPropertyChanged. Lớp sẽ có một thể hiện của từ điển mà nó sẽ sử dụng cho việc thực hiện IDictionary (một trong các phương thức Thêm được mã hóa dưới đây làm ví dụ). Cả hai INotifyCollectionChanged và INotifyProperyChanged đòi hỏi sự hiện diện của các sự kiện, những sự kiện này nên bị sa thải tại các điểm thích hợp trong chức năng wrapper (một lần nữa, tham khảo phương pháp Add dưới đây cho một ví dụ)

class ObservableDictionary<TKey, TValue> : IDictionary, INotifyCollectionChanged, INotifyPropertyChanged 
{ 
    private Dictionary<TKey, TValue> mDictionary; 
    // Methods & Properties for IDictionary implementation would defer to mDictionary: 
    public void Add(TKey key, TValue value){ 
     mDictionary.Add(key, value); 
     OnCollectionChanged(NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value) 
     return; 
    } 
    // Implementation of INotifyCollectionChanged: 
    public event NotifyCollectionChangedEventHandler CollectionChanged; 
    protected void OnCollectionChanged(NotifyCollectionChangedEventArgs args){ 
     // event fire implementation 
    } 
    // Implementation of INotifyProperyChanged: 
    public event ProperyChangedEventHandler ProperyChanged; 
    protected void OnPropertyChanged(PropertyChangedEventArgs args){ 
     // event fire implementation 
    } 
} 

Edit:

Lưu ý rằng một việc thực hiện giao diện IDictionary trực tiếp hoặc gián tiếp sẽ yêu cầu ba giao diện bổ sung được thực hiện:

ICollection<KeyValuePair<TKey,TValue>> 
IEnumerable<KeyValuePair<TKey,TValue>> 
IEnumerable. 

Tùy thuộc vào nhu cầu của bạn mà bạn có thể không phải triển khai toàn bộ IDictionary inte rface, nếu bạn chỉ sẽ được gọi một vài phương pháp sau đó chỉ cần thực hiện những phương pháp và giao diện IDictionary trở thành một sang trọng. Bạn phải triển khai giao diện INotifyCollectionChanged và INotifyPropertyChanged để gắn kết với hoạt động tuy nhiên.Blockquote

+0

đặt điều này vào VS Tôi lưu ý có nhiều phương thức giao diện cần thực hiện hơn - điều này có đúng không? – Greg

+0

Có, nếu yêu cầu của bạn yêu cầu bạn triển khai toàn bộ giao diện IDictionary, hãy xem các chỉnh sửa của tôi –

0

gì về cái gì đó như:

ObservableCollection<Tuple<string, object>>() 

nơi chuỗi và đối tượng và các loại mẫu dĩ nhiên

+1

Tùy thuộc vào cách sử dụng, điều đó có thể hoạt động. Tuy nhiên, hãy xem xét làm thế nào bạn sẽ 'tìm thấy' một yếu tố bằng chìa khóa khi sử dụng tuples như thế này. Một từ điển có thể tìm kiếm một giá trị bằng khóa bằng cách sử dụng băm và có thể nhanh hơn một chút so với việc tìm kiếm danh sách cho một khóa khớp. – MPavlak

+0

Bạn đã thực hiện một điểm. Tuy nhiên, sử dụng một bộ sưu tập quan sát cho các tập dữ liệu khổng lồ có lẽ không phải là một ý tưởng hay. – eka808

0

public class ObservableDictonary: từ điển, INotifyCollectionChanged, INotifyPropertyChanged { sự kiện công cộng NotifyCollectionChangedEventHandler CollectionChanged;

public event PropertyChangedEventHandler PropertyChanged; 

    public new void Add(TKey key, TValue value) 
    { 
     base.Add(key, value); 
     if (!TryGetValue(key, out _)) return; 
     var index = Keys.Count; 
     OnPropertyChanged(nameof(Count)); 
     OnPropertyChanged(nameof(Values)); 
     OnCollectionChanged(NotifyCollectionChangedAction.Add, value, index); 
    } 

    public new void Remove(TKey key) 
    { 
     if (!TryGetValue(key, out var value)) return; 
     var index = IndexOf(Keys, key); 
     OnPropertyChanged(nameof(Count)); 
     OnPropertyChanged(nameof(Values)); 
     OnCollectionChanged(NotifyCollectionChangedAction.Remove, value, index); 
     base.Remove(key); 
    } 

    public new void Clear() 
    { 

    } 

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
     PropertyChanged?.Invoke(this, e); 
    } 

    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     CollectionChanged?.Invoke(this, e); 
    } 

    private void OnPropertyChanged(string propertyName) 
    { 
     OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
    } 

    private void OnCollectionChanged(NotifyCollectionChangedAction action, object item) 
    { 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item)); 
    } 

    private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index) 
    { 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index)); 
    } 

    private int IndexOf(KeyCollection keys, TKey key) 
    { 
     var index = 0; 
     foreach (var k in keys) 
     { 
      if (Equals(k, key)) 
       return index; 
      index++; 
     } 
     return -1; 
    } 
} 

I ovveride Thêm, xóa và xóa. Bạn phải hiểu, nếu bạn sử dụng phương pháp mở rộng hoặc phương thức đơn giản, lấy tham số Dictonary, bạn sẽ không thấy thay đổi, bởi vì trong trường hợp này, phương thức Add or Remove sẽ sử dụng Dictonary (không phải ObservableDictonary). Vì vậy, bạn phải chỉ đạo các phương thức (Thêm hoặc Xóa) của ObservableDictonary

Các vấn đề liên quan