37

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

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

    ...
}

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

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

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

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

我可以做到这一点,那么,怎么做?

4

4 回答 4

53

根据这个博客条目,你必须使用"Item[]". Item 是编译器在使用索引器时生成的属性的名称。

如果您想明确,可以使用IndexerName属性装饰索引器属性。

这将使代码看起来像:

public class IndexerProvider : INotifyPropertyChanged {

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

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

于 2009-03-18T10:27:46.657 回答
17

另外,您可以使用

FirePropertyChanged ("Item[IndexerKeyThingy]");

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

于 2011-08-11T09:29:04.587 回答
7

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

首先是大多数避免魔术属性名称字符串的流行方法是无效的。该[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

其他 几篇文章已经用来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 事件中传递的名称,并且,即使它不关心实际属性的名称(我没有满意地确定它)方式或其他),避免使用[IndexerName]将保持一致性。

于 2014-03-27T19:30:46.603 回答
5

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

public class IndexerProvider : INotifyPropertyChanged {

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

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

于 2010-07-11T17:16:54.477 回答