简体   繁体   English

wpf 绑定 ObservableDictionary

[英]wpf binding ObservableDictionary

I already read some post on stackoverflow but... I can't solve my problem.我已经阅读了有关 stackoverflow 的一些帖子,但是......我无法解决我的问题。

Windows.xaml code Windows.xaml 代码

<StackPanel Orientation="Vertical" Grid.Row="0" Grid.Column="1">
    <TextBox x:Name="txt1" Margin="0,0,300,0" Text="{Binding Path=MyData[Code1], UpdateSourceTrigger=PropertyChanged}" />
    <TextBox x:Name="txt2" Margin="0,0,300,0" Text="{Binding Path=MyData[Code2], UpdateSourceTrigger=PropertyChanged}" />
    <Button Content="Test" Click="Button_Click" Width="300" Margin="10"/>
</StackPanel>

My code-behind (usually I don't use code-behind, but in this way it's easier to show my problem)我的代码隐藏(通常我不使用代码隐藏,但这样更容易显示我的问题)

        public ObservableDictionary<string, string> MyData { get; } = new ObservableDictionary<string, string>();

        public Window4() {
            InitializeComponent();

            DataContext = this;

            MyData.Add("Code1", "Description 1");
            MyData.Add("Code2", "Description 2");
            MyData.Add("Code3", "Description 3");
        }

        private void Button_Click(object sender, RoutedEventArgs e) {
            MyData["Code1"] = "A new description here";
        }

So, I want to bind my observable collection MyData to textboxes.所以,我想将我的可观察集合 MyData 绑定到文本框。 Well, when window started textbox "txt1" has the correct value "Description 1" textbox "txt2" has the correct value "Description 2"好吧,当 window 启动文本框“txt1”具有正确的值“描述 1”文本框“txt2”具有正确的值“描述 2”

Now, clicking on button "txt1" should show "A new description here"... but... nothing happens... Why?现在,点击按钮“txt1”应该会显示“A new description here”......但是......没有任何反应......为什么?

If I put a breakpoint on button click, type a new value on "txt1", I click the button, my observable collection correctly contains the new value I typed...如果我在按钮单击上设置断点,在“txt1”上输入一个新值,然后单击按钮,我的可观察集合正确地包含我输入的新值...

Why textboxes binding works well only at startup?为什么文本框绑定仅在启动时才能正常工作? It's driving me crazy...这让我疯狂...

This is my ObservableDictionary class这是我的 ObservableDictionary class

    [DebuggerDisplay("Count={Count}")]
    public class ObservableDictionary<TKey, TValue> :
        ICollection<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue>,
        INotifyCollectionChanged, INotifyPropertyChanged {
        readonly IDictionary<TKey, TValue> dictionary;

        /// <summary>Event raised when the collection changes.</summary>
        public event NotifyCollectionChangedEventHandler CollectionChanged = (sender, args) => { };

        /// <summary>Event raised when a property on the collection changes.</summary>
        public event PropertyChangedEventHandler PropertyChanged = (sender, args) => { };

        /// <summary>
        /// Initializes an instance of the class.
        /// </summary>
        public ObservableDictionary()
            : this(new Dictionary<TKey, TValue>()) {
        }

        /// <summary>
        /// Initializes an instance of the class using another dictionary as 
        /// the key/value store.
        /// </summary>
        public ObservableDictionary(IDictionary<TKey, TValue> dictionary) {
            this.dictionary = dictionary;
        }

        void AddWithNotification(KeyValuePair<TKey, TValue> item) {
            AddWithNotification(item.Key, item.Value);
        }

        void AddWithNotification(TKey key, TValue value) {
            dictionary.Add(key, value);

            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,
                new KeyValuePair<TKey, TValue>(key, value)));
            PropertyChanged(this, new PropertyChangedEventArgs("Count"));
            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
            PropertyChanged(this, new PropertyChangedEventArgs("Values"));
        }

        bool RemoveWithNotification(TKey key) {
            TValue value;
            if (dictionary.TryGetValue(key, out value) && dictionary.Remove(key)) {
                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove,
                    new KeyValuePair<TKey, TValue>(key, value)));
                PropertyChanged(this, new PropertyChangedEventArgs("Count"));
                PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
                PropertyChanged(this, new PropertyChangedEventArgs("Values"));

                return true;
            }

            return false;
        }

        void UpdateWithNotification(TKey key, TValue value) {
            TValue existing;
            if (dictionary.TryGetValue(key, out existing)) {
                dictionary[key] = value;

                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace,
                    new KeyValuePair<TKey, TValue>(key, value),
                    new KeyValuePair<TKey, TValue>(key, existing)));
                PropertyChanged(this, new PropertyChangedEventArgs("Values"));
            } else {
                AddWithNotification(key, value);
            }
        }

        /// <summary>
        /// Allows derived classes to raise custom property changed events.
        /// </summary>
        protected void RaisePropertyChanged(PropertyChangedEventArgs args) {
            PropertyChanged(this, args);
        }

        #region IDictionary<TKey,TValue> Members

        /// <summary>
        /// Adds an element with the provided key and value to the <see cref="T:System.Collections.Generic.IDictionary`2" />.
        /// </summary>
        /// <param name="key">The object to use as the key of the element to add.</param>
        /// <param name="value">The object to use as the value of the element to add.</param>
        public void Add(TKey key, TValue value) {
            AddWithNotification(key, value);
        }

        /// <summary>
        /// Determines whether the <see cref="T:System.Collections.Generic.IDictionary`2" /> contains an element with the specified key.
        /// </summary>
        /// <param name="key">The key to locate in the <see cref="T:System.Collections.Generic.IDictionary`2" />.</param>
        /// <returns>
        /// true if the <see cref="T:System.Collections.Generic.IDictionary`2" /> contains an element with the key; otherwise, false.
        /// </returns>
        public bool ContainsKey(TKey key) {
            return dictionary.ContainsKey(key);
        }

        /// <summary>
        /// Gets an <see cref="T:System.Collections.Generic.ICollection`1" /> containing the keys of the <see cref="T:System.Collections.Generic.IDictionary`2" />.
        /// </summary>
        /// <returns>An <see cref="T:System.Collections.Generic.ICollection`1" /> containing the keys of the object that implements <see cref="T:System.Collections.Generic.IDictionary`2" />.</returns>
        public ICollection<TKey> Keys {
            get { return dictionary.Keys; }
        }

        /// <summary>
        /// Removes the element with the specified key from the <see cref="T:System.Collections.Generic.IDictionary`2" />.
        /// </summary>
        /// <param name="key">The key of the element to remove.</param>
        /// <returns>
        /// true if the element is successfully removed; otherwise, false.  This method also returns false if <paramref name="key" /> was not found in the original <see cref="T:System.Collections.Generic.IDictionary`2" />.
        /// </returns>
        public bool Remove(TKey key) {
            return RemoveWithNotification(key);
        }

        /// <summary>
        /// Gets the value associated with the specified key.
        /// </summary>
        /// <param name="key">The key whose value to get.</param>
        /// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value" /> parameter. This parameter is passed uninitialized.</param>
        /// <returns>
        /// true if the object that implements <see cref="T:System.Collections.Generic.IDictionary`2" /> contains an element with the specified key; otherwise, false.
        /// </returns>
        public bool TryGetValue(TKey key, out TValue value) {
            return dictionary.TryGetValue(key, out value);
        }

        /// <summary>
        /// Gets an <see cref="T:System.Collections.Generic.ICollection`1" /> containing the values in the <see cref="T:System.Collections.Generic.IDictionary`2" />.
        /// </summary>
        /// <returns>An <see cref="T:System.Collections.Generic.ICollection`1" /> containing the values in the object that implements <see cref="T:System.Collections.Generic.IDictionary`2" />.</returns>
        public ICollection<TValue> Values {
            get { return dictionary.Values; }
        }

        /// <summary>
        /// Gets or sets the element with the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public TValue this[TKey key] {
            get { return dictionary[key]; }
            set { UpdateWithNotification(key, value); }
        }

        #endregion

        #region ICollection<KeyValuePair<TKey,TValue>> Members

        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) {
            AddWithNotification(item);
        }

        void ICollection<KeyValuePair<TKey, TValue>>.Clear() {
            ((ICollection<KeyValuePair<TKey, TValue>>)dictionary).Clear();

            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            PropertyChanged(this, new PropertyChangedEventArgs("Count"));
            PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
            PropertyChanged(this, new PropertyChangedEventArgs("Values"));
        }

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

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

        int ICollection<KeyValuePair<TKey, TValue>>.Count {
            get { return ((ICollection<KeyValuePair<TKey, TValue>>)dictionary).Count; }
        }

        bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
            get { return ((ICollection<KeyValuePair<TKey, TValue>>)dictionary).IsReadOnly; }
        }

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

        #endregion

        #region IEnumerable<KeyValuePair<TKey,TValue>> Members

        IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() {
            return ((ICollection<KeyValuePair<TKey, TValue>>)dictionary).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return ((ICollection<KeyValuePair<TKey, TValue>>)dictionary).GetEnumerator();
        }

        #endregion
    }

Keys and Values are collections in which elements change, but the collections themselves are the same. Keys和Values是collections,其中元素发生变化,但collections本身是一样的。 You create a PropertyChanged with these values, the binding checks that it is the same collection, and then pauses the update.您使用这些值创建一个 PropertyChanged,绑定检查它是否是同一个集合,然后暂停更新。

Create an empty PropertyChanged and then a full update of all values should occur.创建一个空的 PropertyChanged,然后应该对所有值进行完全更新。

Partial example:部分示例:

    public static PropertyChangedEventArgs EmptyPropertyChangedEventArgs {get;}
         = new PropertyChangedEventArgs(string.Empty);
    void AddWithNotification(TKey key, TValue value)
    {
        dictionary.Add(key, value);

        CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,
            new KeyValuePair<TKey, TValue>(key, value)));
        // PropertyChanged(this, new PropertyChangedEventArgs("Count"));
        // PropertyChanged(this, new PropertyChangedEventArgs("Keys"));
        // PropertyChanged(this, new PropertyChangedEventArgs("Values"));
        PropertyChanged(this, EmptyPropertyChangedEventArgs);
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM