Привязка данных не обновляется при использовании {Binding.} Или {Binding} - PullRequest
4 голосов
/ 06 марта 2010

У меня есть ObservableCollection адресов, которые я привязываю к ListBox.Затем в ItemTemplate я привязываюсь к текущей записи адреса, используя {Binding.}.Это приводит к тому, что мои адреса отображаются с использованием метода ToString, который я настроил для форматирования адреса.Все хорошо, за исключением того, что я обновляю свойства отдельной записи адреса, список в пользовательском интерфейсе не обновляется.При добавлении / удалении в список пользовательский интерфейс обновляется (с использованием поведения ObservableCollection).Если я связываюсь напрямую со свойствами по адресу, пользовательский интерфейс обновляется (используя поведение INotifyPropertyChanged объекта Address).

Мой вопрос заключается в том, есть ли способ уведомить пользовательский интерфейс об изменении объекта в целом, чтобы я мог по-прежнему использовать этот синтаксис или мне нужно добавить и установить свойство DisplayText для моего типа адресакоторый вызывает метод ToString и связывается с этим?К вашему сведению, это архитектура MVVM, поэтому я не могу позволить себе роскошь напрямую вызывать Refresh в ListBox.

Спасибо за любую помощь / идеи.

  <ListBox x:Name="AddressList" ItemsSource="{Binding Addresses}" Background="Transparent" BorderBrush="Transparent"
   Width="200" HorizontalAlignment="Left">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel>
          <TextBlock Text="{Binding .}" />
        </StackPanel>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>

Ответы [ 2 ]

3 голосов
/ 06 марта 2010

Когда вы привязываетесь к самому объекту Address, сам объект, то есть его идентичность, не меняется, даже если его свойства изменяются.Поэтому в этом случае WPF не знает, как обновить привязку.

Так что да, вам нужно привязать к уведомляющему свойству (или свойствам), а не ко всему объекту.Как вы говорите, один из способов сделать это - создать свойство DisplayText и вызывать событие PropertyChanged для этого свойства всякий раз, когда что-то, что влияет на отображаемый текст, изменяется.Другой способ - использовать несколько TextBlocks в горизонтально ориентированной StackPanel, каждая из которых привязана к определенному свойству, например,

<StackPanel Orientation="Horizontal">
  <TextBlock Text="{Binding HouseNumber}" />
  <TextBlock Text=", " />
  <TextBlock Text="{Binding Street}" />
  <TextBlock Text=", " />
  <TextBlock Text="{Binding City}" />
</StackPanel>

. Преимущество второго подхода состоит в том, что он дает вам гибкость в пользовательском интерфейсе для изменения способа отображения адресовнапример, несколько строк, форматирование и т. д .;недостатком является то, что это становится сложным, если у вас есть условная логика, например, необязательный плоский номер или вторая адресная строка.

2 голосов
/ 06 марта 2010

Я попытался воспроизвести проблему и все получилось.

Я активировал параметры отладки step-into-NET и увидел, что WPF не прослушивает INotifyPropertyChanged, если путь в привязке пуст.

То, что помогло отразить изменение в списке, - это заменить весь объект в ObservableCollection. Это вызывает INotifyCollectionChanged с действием Replace.

Но это может быть неприемлемо в вашем случае. И это можно увидеть скорее как хак, чем как твердый раствор.

Я бы серьезно подумал о том, чтобы использовать DataTemplate для Address. Там вы должны привязать к нужным вам свойствам (что создаст прослушиватель для INotifyPropertyChanged). Он более гибкий, чем ToString (), и вы можете столкнуться со случаями, когда вам нужно, чтобы ToString () что-то делало для вещей, не относящихся к пользовательскому интерфейсу, что могло бы создать конфликт. И, честно говоря, ToString на самом деле не предназначен для пользовательского интерфейса.

...