2017-04-12 20 views
1

我遇到了一些问题,我的应用程序的速度,并做了一些性能分析。结果表明,在我的应用程序中有很多时间是用linq查询特别是模型的ID。我的想法是创建一个以ID为关键字和模型为Value的可观察字典。这个工程非常好,比LINQ querys快得多与​​C#WPF MVVM获取ObservableList从ObservableDictionary

.Any(x => x.ID == id) 

.First(x => x.ID == id) 

由于ObservableDictionary我用这个样品

http://blogs.microsoft.co.il/shimmy/2010/12/26/observabledictionarylttkey-tvaluegt-c/

现在的问题LINQ查询是我需要创建一个ObservableCollection,我可以绑定到我的视图。我试图扩大与ObservableValue属性的ObservableDictionary但不起作用

 public ObservableCollection<TValue> ObservableValues 
    { 
     get 
     { 
      if (observableValues == null) 
      { 
       lock (lockObject) 
       { 
        if (observableValues == null) 
         observableValues = new ObservableCollection<TValue>(Dictionary.Values); 
       } 
      } 
      return observableValues; 
     } 
    } 

当我一个模型添加到我的字典或更新模型,绑定到视图将不会更新的ObservableCollection。

+0

偏题主题社论:即使在可观察的情况下,字典仍然吸引人。拿那个OD impl把它扔进这个该死的垃圾篮里。抓住你一个闪亮的新KeyedCollection 和螺栓INotifyCollectionChanged和打捞任何INCC impl你可以从OD impl(也许你不应该把它扔在垃圾桶里)。 KeyedCollections是IEnumerable ,其中T有一个属性是关键。 KC可以很好地与WPF绑定一起工作,它们喜欢IE ,但它使用了IEnumerable >字典。 KVP包装让事情变得比他们需要的更难。 – Will

回答

0

感谢您的建议,但我tryed一个KeyedCollection的一些实现,并决定将所有收藏/ Dictionarys切换到我的一个KeyedCollection的自定义实现。性能和字典一样快,但没有使用KVP。下面是我用一些替换方法观察到的实现,它运行速度非常快。

public class ObservableKeyedCollection<TKey, TItem> : KeyedCollection<TKey, TItem>, INotifyCollectionChanged 
{ 
    private const string CountString = "Count"; 
    private readonly Func<TItem, TKey> _getKeyForItemDelegate; 

    // Constructor now requires a delegate to get the key from the item 
    public ObservableKeyedCollection(Func<TItem, TKey> getKeyForItemDelegate) : base() 
    { 
     if (getKeyForItemDelegate == null) 
      throw new ArgumentNullException("Delegate passed can't be null!"); 

     _getKeyForItemDelegate = getKeyForItemDelegate; 
    } 

    protected override TKey GetKeyForItem(TItem item) 
    { 
     return _getKeyForItemDelegate(item); 
    } 

    /// <summary> 
    /// Method to add a new object to the collection, or to replace an existing one if there is 
    /// already an object with the same key in the collection. 
    /// </summary> 
    public void AddOrReplace(TItem newObject) 
    { 
     int i = GetItemIndex(newObject); 
     if (i != -1) 
      SetItem(i, newObject); 
     else 
      Add(newObject); 
    } 


    /// <summary> 
    /// Method to replace an existing object in the collection, i.e., an object with the same key. 
    /// An exception is thrown if there is no existing object with the same key. 
    /// </summary> 
    public void Replace(TItem newObject) 
    { 
     int i = GetItemIndex(newObject); 
     if (i != -1) 
      SetItem(i, newObject); 
     else 
      throw new Exception("Object to be replaced not found in collection."); 
    } 


    /// <summary> 
    /// Method to get the index into the List{} in the base collection for an item that may or may 
    /// not be in the collection. Returns -1 if not found. 
    /// </summary> 
    private int GetItemIndex(TItem itemToFind) 
    { 
     TKey keyToFind = GetKeyForItem(itemToFind); 
     if (this.Contains(keyToFind)) 
      return this.IndexOf(this[keyToFind]); 
     else return -1; 
    } 

    // Overrides a lot of methods that can cause collection change 
    protected override void SetItem(int index, TItem item) 
    { 
     var oldItem = base[index]; 
     base.SetItem(index, item); 
     OnCollectionChanged(NotifyCollectionChangedAction.Replace, item, oldItem); 
    } 

    protected override void InsertItem(int index, TItem item) 
    { 
     base.InsertItem(index, item); 
     OnCollectionChanged(NotifyCollectionChangedAction.Add, item); 
    } 

    protected override void ClearItems() 
    { 
     base.ClearItems(); 
     OnCollectionChanged(); 
    } 

    protected override void RemoveItem(int index) 
    { 
     TItem item = this[index]; 
     base.RemoveItem(index); 
     OnCollectionChanged(NotifyCollectionChangedAction.Remove, item); 
    } 

    private bool _deferNotifyCollectionChanged = false; 
    public void AddRange(IEnumerable<TItem> items) 
    { 
     _deferNotifyCollectionChanged = true; 
     foreach (var item in items) 
      Add(item); 
     _deferNotifyCollectionChanged = false; 

     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     if (_deferNotifyCollectionChanged) 
      return; 

     if (CollectionChanged != null) 
      CollectionChanged(this, e); 
    } 

    #region INotifyCollectionChanged Members 
    public event PropertyChangedEventHandler PropertyChanged; 
    public event NotifyCollectionChangedEventHandler CollectionChanged; 
    private void OnPropertyChanged() 
    { 
     OnPropertyChanged(CountString); 
    } 


    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 


    private void OnCollectionChanged() 
    { 
     if (_deferNotifyCollectionChanged) 
      return; 
     OnPropertyChanged(); 
     if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 


    private void OnCollectionChanged(NotifyCollectionChangedAction action, TItem changedItem) 
    { 
     if (_deferNotifyCollectionChanged) 
      return; 
     OnPropertyChanged(); 
     if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, changedItem)); 
    } 


    private void OnCollectionChanged(NotifyCollectionChangedAction action, TItem newItem, TItem oldItem) 
    { 
     if (_deferNotifyCollectionChanged) 
      return; 
     OnPropertyChanged(); 
     if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItem, oldItem)); 
    } 


    private void OnCollectionChanged(NotifyCollectionChangedAction action, IList newItems) 
    { 
     if (_deferNotifyCollectionChanged) 
      return; 
     OnPropertyChanged(); 
     if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, newItems)); 
    } 
    #endregion 
} 
0

我能想到的最佳解决方案是在您的ObservableDictionnary中保留一个ObservableCollection,其中包含该词典的所有值。

然后,您必须更改班级,以便在插入/更新/删除dicionnary中的值时,它在ObservableCollection中执行相同的操作,从而触发该事件以更新视图。