PropertyChanged для свойства индексатора - PullRequest
33 голосов
/ 18 марта 2009

У меня есть класс со свойством indexer со строковым ключом:

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

    ...
}

Я связываюсь с экземпляром этого класса в WPF, используя запись индексатора:

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

Это прекрасно работает, но я хочу вызвать событие PropertyChanged, когда изменяется одно из значений индексатора. Я попытался поднять его с помощью имени свойства «[имя ключа]» (то есть, включая [] вокруг имени ключа), но, похоже, это не сработало. Я не получаю ошибок привязки в моем окне вывода вообще.

Я не могу использовать CollectionChangedEvent, потому что индекс не основан на целых числах. И технически объект все равно не является коллекцией.

Могу ли я сделать это и так, как?

Ответы [ 4 ]

46 голосов
/ 18 марта 2009

Согласно этой записи в блоге , вы должны использовать "Item[]". Item - это имя свойства, сгенерированного компилятором при использовании индексатора.

Если вы хотите быть явным, вы можете украсить свойство индексатора атрибутом IndexerName .

Это сделало бы код похожим на:

public class IndexerProvider : INotifyPropertyChanged {

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

По крайней мере, это делает намерение более ясным. Я не рекомендую вам менять имя индексатора, если ваш собеседник обнаружил строку "Item[]" в жестком коде, это, вероятно, означает, что WPF не сможет работать с другим именем индексатора.

15 голосов
/ 11 августа 2011

Дополнительно, вы можете использовать

FirePropertyChanged ("Item[IndexerKeyThingy]");

Чтобы уведомить только элементы управления, привязанные к IndexerKeyThingy на вашем индексаторе.

5 голосов
/ 27 марта 2014

При работе с INotifyPropertyChang (ed / ing) и индексаторами есть по крайней мере несколько дополнительных предостережений.

Во-первых, большинство популярных методов избегания строк имен магических свойств неэффективны. В строке, созданной атрибутом [CallerMemberName], в конце отсутствует символ '[]', а у лямбда-выражений-членов проблемы с выражением концепции вообще.

() => 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] будет поддерживать последовательность.

5 голосов
/ 11 июля 2010

На самом деле, я считаю, что установка атрибута IndexerName в «Item» является избыточной. Атрибут IndexerName специально разработан для переименования индекса, если вы хотите присвоить его элементу коллекции другое имя. Таким образом, ваш код может выглядеть примерно так:

public class IndexerProvider : INotifyPropertyChanged {

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

Как только вы установили имя индексатора как хотите, вы можете использовать его в событии FirePropertyChanged.

...