2009-07-08 44 views
25

Tôi đang cố gắng tạo một Lớp Từ điển Quan sát được cho WPF DataBinding trong C#. Tôi tìm thấy một ví dụ tốt đẹp từ Andy ở đây: Two Way Data Binding With a Dictionary in WPFLớp Từ điển Quan sát Chung cho DataBinding/WPF C#

Theo đó, tôi đã cố gắng để thay đổi mã để sau:

class ObservableDictionary : ViewModelBase 
{ 
    public ObservableDictionary(Dictionary<TKey, TValue> dictionary) 
    { 
     _data = dictionary; 
    } 

    private Dictionary<TKey, TValue> _data; 

    public Dictionary<TKey, TValue> Data 
    { 
     get { return this._data; } 
    } 

    private KeyValuePair<TKey, TValue>? _selectedKey = null; 
    public KeyValuePair<TKey, TValue>? SelectedKey 
    { 
     get { return _selectedKey; } 
     set 
     { 
      _selectedKey = value; 
      RaisePropertyChanged("SelectedKey"); 
      RaisePropertyChanged("SelectedValue"); 
     } 
    } 

    public TValue SelectedValue 
    { 
     get 
     { 
      return _data[SelectedKey.Value.Key]; 
     } 
     set 
     { 
      _data[SelectedKey.Value.Key] = value; 
      RaisePropertyChanged("SelectedValue"); 
     } 
    } 
} 

}

Đáng tiếc là tôi vẫn không biết làm thế nào để vượt qua "chung" đối tượng từ điển .. bất kỳ ý tưởng?

Cảm ơn bạn!

Cheers

+0

bạn có thể đưa ra một chút chi tiết hơn về những gì bạn đang cố gắng để làm gì? Bạn có thể hiển thị ví dụ về mã mà bạn muốn có thể viết khi bạn nói "chuyển một từ điển chung ..." – JMarsch

+0

Tôi có các từ điển khác nhau cho ví dụ: Mã Bưu điện và Thành phố. Những gì tôi đang cố gắng làm là: - Liên kết dữ liệu (Mô hình/từ điển) với WPF ItemsControl của tôi, vì vậy người dùng có thể, ví dụ: thay đổi thành phố của mã bưu chính và mô hình được cập nhật tự động. Thật không may chỉ OneWay-ràng buộc là có thể với từ điển "bình thường", bởi vì tôi cần INotifyPropertyChanged. - Tạo một ObservableDictionary, mà thực hiện INotifyPropertyChanged và cũng có chứa một từ điển –

+0

Các giải pháp là có: http://stackoverflow.com/questions/5663395/net-observabledictionary –

Trả lời

35

Nếu bạn thực sự muốn làm một ObservableDictionary, tôi muốn khuyên bạn nên tạo một lớp mà thực hiện cả hai IDictionaryINotifyCollectionChanged. Bạn luôn có thể sử dụng Dictionary nội bộ để thực hiện các phương thức IDictionary để bạn không phải tự mình thực hiện lại.

Vì bạn có kiến ​​thức đầy đủ về thời điểm nội bộ Dictionary thay đổi, bạn có thể sử dụng kiến ​​thức đó để triển khai INotifyCollectionChanged.

+2

bất kỳ cơ hội bạn có thể xây dựng với mã? bạn sẽ được giúp đỡ rất nhiều noobs (như tôi) trawling stackOverflow cho câu trả lời - 23k lượt xem rồi. chrs – BKSpurgeon

+2

@BKSpurgeon Có một mẫu đã có sẵn: http://blogs.microsoft.co.il/shimmy/2010/12/26/observabledictionarylttkey-tvaluegt-c/ (thông qua http://stackoverflow.com/questions/5663395/net-observabledictionary, được liên kết trong phần bình luận của câu hỏi). – Andy

0

Bạn không thể viết cái gì đó sẽ làm cho từ điển của người khác, hãy để một mình IDictionary, quan sát mà không sử dụng một số hình thức phản ánh. Vấn đề là từ điển có thể là một lớp con với các bộ đột biến bổ sung (nói, sắp xếp, hoặc bộ lọc, hoặc bất kỳ điều gì) mà không gọi Add và Remove và bỏ qua các sự kiện của bạn như là kết quả.

Tôi tin rằng các khung công tác tạo mã tồn tại cho phép bạn làm những việc như thế này nhưng tôi không quen thuộc với chúng.

19
+0

Tôi dường như không thể triển khai INotifyCollectionChanged. Nó nói mất tích lắp ráp. Tôi đã nhập tất cả các hội đồng ở đầu bài đăng của bạn (C#) và tôi có .NET 3.5 nhưng không thể tìm thấy nó. Ý tưởng nào? – Joshua

+0

Bạn đã nhập không gian tên, nhưng có lẽ có thiếu tham chiếu đến các hội đồng quan trọng. Hãy chắc chắn rằng System.dll lắp ráp được tham chiếu trong dự án của bạn. Xem ví dụ tại đây (http://i.stack.imgur.com/4kLAB.png). – Shimmy

6

Vì mục đích lịch sử và đặt mọi người trên con đường "hiện tại" ... Đó là tôi mportant biết rằng Microsoft bây giờ giải quyết yêu cầu này trong Windows Store "Basic Page" mẫu của họ trong Visual Studio 2012. Để hỗ trợ LayoutAwarePage họ tạo ra một lớp ObservableDictionary riêng.

Tuy nhiên, họ triển khai giao diện IObservableMap mới thay vì trực tiếp từ điển IDictionary. Giao diện này thêm một sự kiện MapChanged và MapChangedEventHandler, được định nghĩa trong không gian tên Windows.Foundation.Collections.

Đoạn dưới đây chỉ là lớp ObservableDictionary từ LayoutAwarePage.cs tạo ra trong thư mục "chung" của dự án của bạn:

/// <summary> 
    /// Implementation of IObservableMap that supports reentrancy for use as a default view 
    /// model. 
    /// </summary> 
    private class ObservableDictionary<K, V> : IObservableMap<K, V> 
    { 
     private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<K> 
     { 
      public ObservableDictionaryChangedEventArgs(CollectionChange change, K key) 
      { 
       CollectionChange = change; 
       Key = key; 
      } 

      public CollectionChange CollectionChange { get; private set; } 
      public K Key { get; private set; } 
     } 

     private Dictionary<K, V> _dictionary = new Dictionary<K, V>(); 
     public event MapChangedEventHandler<K, V> MapChanged; 

     private void InvokeMapChanged(CollectionChange change, K key) 
     { 
      var eventHandler = MapChanged; 
      if (eventHandler != null) 
      { 
       eventHandler(this, new ObservableDictionaryChangedEventArgs(change, key)); 
      } 
     } 

     public void Add(K key, V value) 
     { 
      _dictionary.Add(key, value); 
      InvokeMapChanged(CollectionChange.ItemInserted, key); 
     } 

     public void Add(KeyValuePair<K, V> item) 
     { 
      Add(item.Key, item.Value); 
     } 

     public bool Remove(K key) 
     { 
      if (_dictionary.Remove(key)) 
      { 
       InvokeMapChanged(CollectionChange.ItemRemoved, key); 
       return true; 
      } 
      return false; 
     } 

     public bool Remove(KeyValuePair<K, V> item) 
     { 
      V currentValue; 
      if (_dictionary.TryGetValue(item.Key, out currentValue) && 
       Object.Equals(item.Value, currentValue) && _dictionary.Remove(item.Key)) 
      { 
       InvokeMapChanged(CollectionChange.ItemRemoved, item.Key); 
       return true; 
      } 
      return false; 
     } 

     public V this[K key] 
     { 
      get 
      { 
       return _dictionary[key]; 
      } 
      set 
      { 
       _dictionary[key] = value; 
       InvokeMapChanged(CollectionChange.ItemChanged, key); 
      } 
     } 

     public void Clear() 
     { 
      var priorKeys = _dictionary.Keys.ToArray(); 
      _dictionary.Clear(); 
      foreach (var key in priorKeys) 
      { 
       InvokeMapChanged(CollectionChange.ItemRemoved, key); 
      } 
     } 

     public ICollection<K> Keys 
     { 
      get { return _dictionary.Keys; } 
     } 

     public bool ContainsKey(K key) 
     { 
      return _dictionary.ContainsKey(key); 
     } 

     public bool TryGetValue(K key, out V value) 
     { 
      return _dictionary.TryGetValue(key, out value); 
     } 

     public ICollection<V> Values 
     { 
      get { return _dictionary.Values; } 
     } 

     public bool Contains(KeyValuePair<K, V> item) 
     { 
      return _dictionary.Contains(item); 
     } 

     public int Count 
     { 
      get { return _dictionary.Count; } 
     } 

     public bool IsReadOnly 
     { 
      get { return false; } 
     } 

     public IEnumerator<KeyValuePair<K, V>> GetEnumerator() 
     { 
      return _dictionary.GetEnumerator(); 
     } 

     System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
     { 
      return _dictionary.GetEnumerator(); 
     } 

     public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex) 
     { 
      if (array == null) throw new ArgumentNullException("array"); 
      int arraySize = array.Length; 
      foreach (var pair in _dictionary) 
      { 
       if (arrayIndex >= arraySize) break; 
       array[arrayIndex++] = pair; 
      } 
     } 
    } 

kiểm tra sâu hơn về không gian tên Windows.Foundation.Collections mới cho thấy một tải trọng giao diện mới được xác định, nhưng chỉ thực hiện một lớp PropertySet. Trên thực tế điều này có vẻ giống như một ObservableDictionary khá tốt chính nó. Nhưng phải có một lý do tại sao MS vẫn tạo ra một ObservableDictionary riêng.Vì vậy, kiểm tra thêm là cần thiết ở đây để xác định ưu và khuyết điểm.

Tóm lại, hoặc PropertySet hoặc IOBServableMap dựa trên ObservableDictionary của bạn phải giải quyết các yêu cầu ngay lập tức cho các dự án "hiện tại" Windows 8 và Điện thoại 8. Tuy nhiên đối với các framework cũ hơn (WPF 4 và Phone 7.5) vẫn còn nhiều việc phải làm.

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