Как обновить IValueConverter на CollectionChanged?

Вот основной пример, чтобы объяснить мою проблему. Допустим, у меня есть

ObservableCollection<int> Numbers {get; set;}

и IValueConverter, который возвращает сумму чисел.

Обычно я бы изменил IValueConverter на IMultiValueConverter и связал второе значение с Numbers.Count, как это

<MultiBinding Converter="{StaticResource SumTheIntegersConverter}">
    <Binding Path="Numbers"     />
    <Binding Path="Numbers.Count"   />
</MultiBinding>

Однако я не могу использовать этот метод для решения моей актуальной проблемы. Похоже, должен быть лучший способ обновить привязку при изменении коллекции, о которой я просто не думаю. Как лучше всего запустить конвертер значений при добавлении и удалении элементов в Numbers?

4 ответа

Решение

Я закончил тем, что делал что-то подобное, что, кажется, работает. Это далеко не оптимальное решение, и я все еще буду интересоваться чем-то лучшим, но, похоже, оно будет работать для моих целей.

class CollectionChangedHandlingValueConverter : IValueConverter
{
    DependencyObject myTarget;
    DependencyProperty myTargetProperty;

    //If this ever needs to be called from XAML you can make it a MarkupExtension and use ProvideValue to set up the Target and TargetProperty
    public CollectionChangedHandlingValueConverter(DependencyObject target, DependencyProperty dp)
    {
        myTarget = target;
        myTargetProperty = dp;
    }

    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        INotifyCollectionChanged collection = value as INotifyCollectionChanged;
        if (collection != null)
        {
            //It notifies of collection changed, try again when it changes
            collection.CollectionChanged += DataCollectionChanged;
        }

        //Do whatever conversions here
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion

    void DataCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if ((myTarget != null) && (myTargetProperty != null))
        {
            BindingOperations.GetBindingExpressionBase(myTarget, myTargetProperty).UpdateTarget();
        }
    }
}

В вашей модели подпишитесь на CollectionChanged и поднимите PropertyChanged:

Numbers.CollectionChanged += (o,e) => 
  OnPropertyChanged(new PropertyChangedEventArgs(nameof(Numbers)));

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

Я написал образец в галерее выражений Microsoft под названием " Агрегатор коллекций", в котором показан рабочий, хотя и сложный, подход к выполнению этой работы с помощью поведения, которое выполняет агрегацию (в вашем случае Count, хотя я также поддерживаю Sum, Average и т. Д.) Для ты, а не конвертер.

И я закончил синхронизировать коллекцию (оригинал с конвертером), посмотрите на основание моего поста, например:

http://alexburtsev.wordpress.com/2011/03/05/mvvm-pattern-in-silverlight-and-wpf/

Другие вопросы по тегам