Почему конвертер не вызывается при изменении коллекции?
Я сделал CollectionToStringConverter
который может конвертировать любой IList
в строку через запятую (например, "Item1, Item2, Item3").
Я использую это так:
<TextBlock Text="{Binding Items,
Converter={StaticResource CollectionToStringConverter}}" />
Выше работает, но только один раз, когда я загружаю пользовательский интерфейс. Items
является ObservableCollection
, Текстовый блок не обновляется, и конвертер не вызывается при добавлении или удалении из Items
,
Любая идея, что не хватает, чтобы сделать эту работу?
2 ответа
Привязка к свойству, дающему коллекцию. Он вступает в силу всякий раз, когда изменяется сам экземпляр коллекции, а не когда изменяются элементы в коллекции.
Есть немало способов достичь желаемого поведения, в том числе:
1) Привязать ItemsControl
для сбора и настройки ItemTemplate
выводить текст, которому предшествует запятая, если это не последний элемент в коллекции. Что-то вроде:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<TextBlock>
<TextBlock Visibility="{Binding RelativeSource={RelativeSource PreviousData}, Converter={StaticResource PreviousDataConverter}}" Text=", "/>
<TextBlock Text="{Binding .}"/>
</TextBlock>
</ItemsControl.ItemTemplate>
</ItemsControl>
2) Напишите код в своем коде, чтобы следить за изменениями в коллекции и обновлять отдельное свойство, объединяющее элементы в один string
, Что-то вроде:
public ctor()
{
_items = new ObservableCollection<string>();
_items.CollectionChanged += delegate
{
UpdateDisplayString();
};
}
private void UpdateDisplayString()
{
var sb = new StringBuilder();
//do concatentation
DisplayString = sb.ToString();
}
3) написать свой ObservableCollection<T>
подкласс, который поддерживает отдельную каскадную строку, аналогичную #2.
Конвертер будет вызываться только при изменении свойства. В этом случае значение "Предметы" не меняется. Когда вы добавляете или удаляете новые элементы в коллекции, связывающая часть не знает об этом.
Вы можете расширить ObservableCollection и добавить в него новое свойство String. Помните, что нужно обновить это свойство в обработчике событий CollectionChanged.
Вот реализация
public class SpecialCollection : ObservableCollection<string>, INotifyPropertyChanged
{
public string CollectionString
{
get { return _CollectionString; }
set {
_CollectionString = value;
FirePropertyChangedNotification("CollectionString");
}
}
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
string str = "";
foreach (string s in this)
{
str += s+",";
}
CollectionString = str;
base.OnCollectionChanged(e);
}
private void FirePropertyChangedNotification(string propName)
{
if (PropertyChangedEvent != null)
PropertyChangedEvent(this,
new PropertyChangedEventArgs(propName));
}
private string _CollectionString;
public event PropertyChangedEventHandler PropertyChangedEvent;
}
И ваш XAML будет похож
<TextBlock DataContext={Binding specialItems} Text="{Binding CollectionString}" />