【问题标题】:Notify that certain value has changed in Dictionary通知字典中的某些值已更改
【发布时间】:2013-01-14 08:15:26
【问题描述】:

目前我正在编写实现INotifyPropertyChanged 的自己的字典。见下文:

public event PropertyChangedEventHandler PropertyChanged;

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

new public Item this[TKey key]
{
    get { return base.Item[key]; }
    set(TValue value)
    {
        if (base.Item[key] != value)
        {
            base.Item[key] = value;
            OnPropertyChanged("XXX"); // what string should I use?
        }
    }
}

我的目标很简单:当 Dictionary 中的某个值发生变化时,通知它发生了变化。然后,所有与相应键名绑定的 WPF 元素都应自行更新。

现在我的问题是:我应该使用什么字符串作为propertyName 来通知?

我试过"[" + key.ToString() + "]""Item[" + key.ToString() + "]" 和简单的key.ToString()。它们似乎都不起作用,因为 WPF 元素没有更新。

使用String.Empty ("") 确实会更新 WPF 元素,但我没有使用它,因为这将更新所有绑定同一个字典的 WPF 元素,即使它们具有不同的键。


这就是我的绑定在 XAML 中的样子:

<TextBlock DataContext="{Binding Dictionary}" Text="{Binding [Index]}" />

Index 当然是我字典中的键名。


有些人建议使用INotifyCollectionChanged,而不是使用INotifyPropertyChanged。我试过这个:

Dim index As Integer = MyBase.Keys.ToList().IndexOf(key)
Dim changedItem As Object = MyBase.ToList().ElementAt(index)

RaiseEvent CollectionChanged(Me, New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, changedItem, index))

但这也不会更新绑定的 WPF 元素。

【问题讨论】:

  • 也许this code article 有帮助?
  • @J.Steen,不幸的是,即使只有一个更改,该实现也会通知 所有 属性。我正在寻找一种更简洁的方法,它只会更新实际发生变化的属性。
  • 当。嗯,值得一试。很抱歉占用您的时间。 =)
  • 我不确定这与问题有关,但由于您使用new 声明索引器属性,因此任何通过IDictionary&lt;Key,Valye&gt; 接口访问字典的代码都不会调用它(或基类引用)。
  • @Olly,是的,我意识到这一点,不,这与问题无关:)

标签: .net wpf dictionary key inotifypropertychanged


【解决方案1】:

也许您需要考虑INotifyCollectionChanged 接口而不是INotifyPropertyChanged。如果是这种情况,请查看 this question 及其链接到的博客文章。

另外,请查看this answer 以查看与您的问题类似的上一个问题。它建议您使用Binding.IndexerName 的值作为更改通知的属性名称。

编辑:

如果您想避免使用INotifyCollectionChanged,您可以尝试另一种方法。更改您的字典,使其值的类型是实现INotifyPropertyChanged 的代理对象。

public class MyProxy<T> : INotifyPropertyChanged
{
    public T Value
    {
        // Getter and setter with change notification code here.
    }
}

然后将这种类型的实例插入到您的字典中一次。将更新字典中值的代码替换为检索代理的代码,然后更新其Value 属性。

您需要将 XAML 绑定更改为 ([Item]).Value 之类的内容。

在查看了您的其他一些 cmets 之后,看起来这种方法确实适合您。这类似于我最近必须做的事情。创建自定义KeyedCollection 和相应的代理。向代理添加ItemName 属性;只读,不需要支持变更通知。在 ItemName 属性上创建您的 KeyedCollection 实现索引。工作一种享受!如果您愿意,我会添加示例代码。

【讨论】:

  • 不,INotifyCollectionChanged 不关心集合内的属性更改。它只会在添加、删除、移动、替换项目或重置整个集合时通知其他人。此接口在将整个集合绑定到 ItemsSource 时很有用,但它不适合我的需要。
  • @Ruud,我添加了指向另一篇可能有用的帖子的链接。
  • 非常感谢您的意见,但不幸的是,使用 Binding.IndexerName"Item[]" 相同,您可能猜到,它将更新 all 键。我开始认为不可能通知在某个索引/键处发生的更改。
  • @RuudLenders - 嗯,我明白了你的问题。我真的认为这比INotifyPropertyChanged 更接近INotifyCollectionChanged 行为。实际上,当您更改与给定键对应的值时,您正在替换Dictionary.Values 集合中的一个项目。这对应于NotifyCollectionChangedAction 枚举的Replace 成员。 indexer 属性在概念上只是这些底层集合结构的方便包装。
  • @RuudLenders 您的索引器实现建议您希望在集合中的项目被替换时发送通知(而不是在项目的某些属性发生更改时)。 INotifyCollectionChanged 通过引发 CollectionChanged 事件来支持这种情况,其 Action 值为 NotifyCollectionChangedAction.Replace
【解决方案2】:
if (base.Item[key] != value)
{
     base.Item[key] = value;
     if (key == "notifykey") OnPropertyChanged("[Item]");
}

String.empty 将通知所有属性,而不仅仅是 Item

每个操作都是字典的所有绑定问题仍然更新。
所以我会做一个新的财产

假设你的值是字符串 绑定到 KeyedValue

public String KeyedValue
{
    get { return base.Item[Index]; }
}

if (key == "Index") OnPropertyChanged("KeyedValue");

【讨论】:

  • 奇怪的是,这也不起作用。我会更新我的答案,这样你就可以看到我是如何设置绑定的,也许问题来自那里。
  • 哇,OnPropertyChanged("") 更新了一切——对吗?然后必须有一个正确的值。覆盖面,但尝试不使用新的。
  • new 是必需的,因为我从 Dictionary 类本身继承了该属性。我发现使用"Item[]" 作为属性名称确实有效。但是,这样与其他键的绑定也会更新。
  • 使用属性正是我目前试图避免的:P 我目前有 50 多个属性,这就是为什么我希望使用 Dictionary(Of String, Object) 会使我的代码更简单。
  • 我以为只有一个 KeyedValue 而另一个根本没有。您应该在问题中更清楚地说明这一点。在一个属性上,你要么触发 Notify,要么不触发。如果您有 50 多个绑定,那么我将只创建 50 多个属性。
猜你喜欢
  • 2011-06-25
  • 1970-01-01
  • 1970-01-01
  • 2019-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
相关资源
最近更新 更多