c# - ObservableDictionary 初始化

标签 c# wpf

我已经实现了一个ObservableDictionary(代码粘贴在下面)。如果我使用重载的 ctor 初始化 ObservableDictionary

public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
{
    dictionary = new Dictionary<TKey, TValue>(dictionary);
}

通过

var d = Helpers.GetAvailableSelections((Taurus.Market)MarketFilter.SelectedItem)
    .ToDictionary(t => t.ToString(), t => (object)t);
SelectionItems = new ObservableDictionary<string, object>(d);

在我的 WPF 应用程序 SelectionItems 的一种情况下,内部 Dictionary 为 null。如果我使用默认的 ctor 然后“手动”添加项目

var d = Helpers.GetAvailableSelections((Taurus.Market)MarketFilter.SelectedItem)
    .ToDictionary(t => t.ToString(), t => (object)t);
SelectionItems = new ObservableDictionary<string, object>();
foreach (var kvp in d)
    SelectionItems.Add(kvp);

一切都很好。我查看了代码,似乎无法理解为什么会这样。当我单步执行时,内部 Dictionary 设置正确,并且此代码在 MainThread(UI 线程)上执行的线程,因此这似乎不是线程问题。

为什么会发生这种情况?

感谢您的宝贵时间。


ObservableDictionary 代码:

public class ObservableDictionary<TKey, TValue> : 
    IDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
{
    private const string CountString = "Count";
    private const string IndexerName = "Item[]";
    private const string KeysName = "Keys";
    private const string ValuesName = "Values";

    private IDictionary<TKey, TValue> dictionary;
    protected IDictionary<TKey, TValue> Dictionary
    {
        get { return dictionary; }
    }

    #region Constructors
    public ObservableDictionary()
    {
        dictionary = new Dictionary<TKey, TValue>();
    }
    public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
    {
        dictionary = new Dictionary<TKey, TValue>(dictionary);
    }
    public ObservableDictionary(IEqualityComparer<TKey> comparer)
    {
        dictionary = new Dictionary<TKey, TValue>(comparer);
    }
    public ObservableDictionary(int capacity)
    {
        dictionary = new Dictionary<TKey, TValue>(capacity);
    }
    public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
    {
        dictionary = new Dictionary<TKey, TValue>(dictionary, comparer);
    }
    public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer)
    {
        dictionary = new Dictionary<TKey, TValue>(capacity, comparer);
    }
    #endregion

    #region IDictionary<TKey,TValue> Members
    public void Add(TKey key, TValue value)
    {
        Insert(key, value, true);
    }

    public bool ContainsKey(TKey key)
    {
        return Dictionary.ContainsKey(key);
    }

    public ICollection<TKey> Keys
    {
        get { return Dictionary.Keys; }
    }

    public bool Remove(TKey key)
    {
        if (key == null) throw new ArgumentNullException("key");

        TValue value;
        Dictionary.TryGetValue(key, out value);
        var removed = Dictionary.Remove(key);
        if (removed)
            //OnCollectionChanged(NotifyCollectionChangedAction.Remove, new KeyValuePair<TKey, TValue>(key, value));
            OnCollectionChanged();
        return removed;
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        return Dictionary.TryGetValue(key, out value);
    }

    public ICollection<TValue> Values
    {
        get { return Dictionary.Values; }
    }

    public TValue this[TKey key]
    {
        get
        {
            TValue value;
            return TryGetValue(key, out value) ? value : default(TValue);
        }
        set
        {
            Insert(key, value, false);
        }
    }

    #endregion

    #region ICollection<KeyValuePair<TKey,TValue>> Members
    public void Add(KeyValuePair<TKey, TValue> item)
    {
        Insert(item.Key, item.Value, true);
    }

    public void Clear()
    {
        if (Dictionary.Count > 0)
        {
            Dictionary.Clear();
            OnCollectionChanged();
        }
    }

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        return Dictionary.Contains(item);
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        Dictionary.CopyTo(array, arrayIndex);
    }

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

    public bool IsReadOnly
    {
        get { return Dictionary.IsReadOnly; }
    }

    public bool Remove(KeyValuePair<TKey, TValue> item)
    {
        return Remove(item.Key);
    }


    #endregion

    #region IEnumerable<KeyValuePair<TKey,TValue>> Members
    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return Dictionary.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members
    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable)Dictionary).GetEnumerator();
    }
    #endregion

    #region INotifyCollectionChanged Members
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    #endregion

    #region INotifyPropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion

    public void AddRange(IDictionary<TKey, TValue> items)
    {
        if (items == null) throw new ArgumentNullException("items");

        if (items.Count > 0)
        {
            if (Dictionary.Count > 0)
            {
                if (items.Keys.Any((k) => Dictionary.ContainsKey(k)))
                    throw new ArgumentException("An item with the same key has already been added.");
                else
                    foreach (var item in items) Dictionary.Add(item);
            }
            else
                dictionary = new Dictionary<TKey, TValue>(items);
            OnCollectionChanged(NotifyCollectionChangedAction.Add, items.ToArray());
        }
    }

    private void Insert(TKey key, TValue value, bool add)
    {
        if (key == null) throw new ArgumentNullException("key");

        TValue item;
        if (Dictionary.TryGetValue(key, out item))
        {
            if (add) throw new ArgumentException("An item with the same key has already been added.");
            if (Equals(item, value)) return;
            Dictionary[key] = value;

            OnCollectionChanged(NotifyCollectionChangedAction.Replace, 
                new KeyValuePair<TKey, TValue>(key, value), new KeyValuePair<TKey, TValue>(key, item));
            OnPropertyChanged(key.ToString());
        }
        else
        {
            Dictionary[key] = value;

            OnCollectionChanged(NotifyCollectionChangedAction.Add, 
                new KeyValuePair<TKey, TValue>(key, value));
            OnPropertyChanged(key.ToString());
        }
    }

    private void OnPropertyChanged()
    {
        OnPropertyChanged(CountString);
        OnPropertyChanged(IndexerName);
        OnPropertyChanged(KeysName);
        OnPropertyChanged(ValuesName);
    }

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

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

    private void OnCollectionChanged(NotifyCollectionChangedAction action, 
        KeyValuePair<TKey, TValue> changedItem)
    {
        OnPropertyChanged();
        if (CollectionChanged != null) CollectionChanged(this, 
            new NotifyCollectionChangedEventArgs(action, changedItem, 0));
    }

    private void OnCollectionChanged(NotifyCollectionChangedAction action, 
        KeyValuePair<TKey, TValue> newItem, KeyValuePair<TKey, TValue> oldItem)
    {
        OnPropertyChanged();
        if (CollectionChanged != null) CollectionChanged(this, 
            new NotifyCollectionChangedEventArgs(action, newItem, oldItem, 0));
    }

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

最佳答案

这个构造函数是问题所在:

public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
{
    dictionary = new Dictionary<TKey, TValue>(dictionary);
}

这是将新值分配给参数,而不是分配给字段,因为这是 block 中名称dictionary 的含义。你需要用 this 来限定它:

public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
{
    this.dictionary = new Dictionary<TKey, TValue>(dictionary);
}

关于c# - ObservableDictionary 初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32538722/

相关文章:

c# - 如何使用 CrystalReport 对象和 TableAdapter 将 Crystal Report 导出到 Excel?

c# - 静态 IDisposable 字典模式

c# - 嵌入的图像显示为损坏

c# - GridView 检索每一行中的数据

wpf - 替换 RichTextBox 文本但保持格式

c# - 是否有用于获取图标的 Windows 7 颜色的 API?

c# - PropertyChanged 影响多个属性

c# - 为 Windows Phone 创建 PIN 查找框

c# - 上传和接收使用 ASP.NET 进行 http 压缩的大文件会给出 "unexpected end of mime multipart stream"

wpf - MaterialDesign 运行时更改主题 Wpf