【问题标题】:PropertyChanged for indexer property索引器属性的 PropertyChanged
【发布时间】:2010-10-14 01:09:10
【问题描述】:

我有一个带有索引器属性的类,带有一个字符串键:

public class IndexerProvider {
    public object this[string key] {
        get
        {
            return ...
        }
        set
        {
            ...
        }
    }

    ...
}

我在 WPF 中绑定到此类的一个实例,使用索引器表示法:

<TextBox Text="{Binding [IndexerKeyThingy]}">

这很好,但我想在索引器值之一更改时引发PropertyChanged 事件。我尝试使用“[keyname]”的属性名称来提升它(即在密钥名称周围包含 []),但这似乎不起作用。我的输出窗口中没有任何绑定错误。

我不能使用 CollectionChangedEvent,因为索引不是基于整数的。而且从技术上讲,对象无论如何都不是一个集合。

我可以这样做吗?那么,怎么做?

【问题讨论】:

    标签: c# wpf data-binding indexer


    【解决方案1】:

    根据this blog entry,你必须使用"Item[]"。 Item 是编译器在使用索引器时生成的属性的名称。

    如果你想明确一点,你可以用IndexerName 属性装饰索引器属性。

    这将使代码看起来像:

    public class IndexerProvider : INotifyPropertyChanged {
    
        [IndexerName ("Item")]
        public object this [string key] {
            get {
                return ...;
            }
            set {
                ... = value;
                FirePropertyChanged ("Item[]");
            }
        }
    }
    

    至少它使意图更加清晰。不过我不建议您更改索引器名称,如果您的朋友发现字符串"Item[]" 是硬编码的,则可能意味着 WPF 将无法处理不同的索引器名称。

    【讨论】:

    • 效果很好。奇怪的是,我在 Google 搜索中错过了那篇博文。
    • 这个解决方案效果很好,但它有一个烦人的限制:你不能指定只为一个键更改值......所以如果你有许多键的绑定,它们都会被刷新
    • 几年后,现在有了“nameof”关键字。我在所有FirePropertyChange 调用中都使用它,但你能以任何方式nameof 索引器吗?
    • 不确定在 FirePropertyChanged 中实现了什么,但使用 OnPropertyChanged("Item") 是至少在 Xamarin Forms 中唯一有效的代码。不知道为什么附加[]这么麻烦。
    • 您应该使用 Binding.IndexerName (docs.microsoft.com/fr-fr/dotnet/api/…) 而不是硬编码“Item[]”
    【解决方案2】:

    另外,你可以使用

    FirePropertyChanged ("Item[IndexerKeyThingy]");
    

    仅通知绑定到您的索引器上的 IndexerKeyThingy 的控件。

    【讨论】:

    • +1 知道你可以根据字典条目提高它很有用
    • 有人成功地让它工作了吗?它不适合我。似乎只有“Item[]”会触发更新。
    • 它在 Silverlight 4/5 上运行良好,但在 WPF 4.6.2 上它根本不起作用。还是得用Item[]。
    • 这是一个离散的INotifyCollectionChanged 行为!我想知道这是否适用于 Xamarin.Forms。
    • 在多维数组中怎么样?
    【解决方案3】:

    在处理 INotifyPropertyChang(ed/ing) 和索引器时,至少还有一些额外的注意事项。

    首先是大多数popular methods避免魔术属性名称字符串是无效的。 [CallerMemberName] 属性创建的字符串末尾缺少 '[]',而 lambda 成员表达式在表达概念方面完全有问题。

    () => this[]  //Is invalid
    () => this[i] //Is a method call expression on get_Item(TIndex i)
    () => this    //Is a constant expression on the base object
    

    几个otherposts 使用Binding.IndexerName 来避免字符串文字"Item[]",这是合理的,但会引发第二个潜在问题。对 WPF 相关部分的拆解的调查在 PropertyPath.ResolvePathParts 中发现了以下部分。

    if (this._arySVI[i].type == SourceValueType.Indexer)
      {
        IndexerParameterInfo[] array = this.ResolveIndexerParams(this._arySVI[i].paramList, obj, throwOnError);
        this._earlyBoundPathParts[i] = array;
        this._arySVI[i].propertyName = "Item[]";
      }
    

    重复使用"Item[]" 作为常量值表明 WPF 期望这是在 PropertyChanged 事件中传递的名称,即使它不关心实际属性的名称(我没有t 以一种或另一种方式确定令我满意),避免使用 [IndexerName] 将保持一致性。

    【讨论】:

      【解决方案4】:

      实际上,我认为将 IndexerName 属性设置为“Item”是多余的。 IndexerName 属性专门设计用于重命名索引,如果你想给它的集合项一个不同的名称。所以你的代码可能看起来像这样:

      public class IndexerProvider : INotifyPropertyChanged {
      
          [IndexerName("myIndexItem")]
          public object this [string key] {
              get {
                  return ...;
              }
              set {
                  ... = value;
                  FirePropertyChanged ("myIndexItem[]");
              }
          }
      }
      

      将索引器名称设置为您想要的任何名称后,您就可以在 FirePropertyChanged 事件中使用它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-16
        • 1970-01-01
        • 2015-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-02
        • 1970-01-01
        相关资源
        最近更新 更多