1
votes

I have a pretty straightforward IValueConverter that converts a IList<string> into a comma separated string of strings. Trouble is the collection (which is a ObservableCollection) is not attempting to update the text, I can tell because a debug point in the IValueConverter shows that is is not being called after the initial binding on load.

The converter (This part seems to work fine when actually called)

public class CollectionToCommaSeperatedString : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return parameter.ToString();
        if (((IList<string>)value).Count > 0)
            return String.Join(", ", ((IList<string>)value).ToArray()) ?? parameter.ToString();
        else
            return parameter.ToString();
    }

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

The bound element:

<TextBlock Text="{Binding SelectedChannels, ConverterParameter='(Click to select channels)', Converter={StaticResource CollectionToCommaSeperatedString}, ElementName=userControl, Mode=OneWay}" HorizontalAlignment="Left" VerticalAlignment="Top"/>

The CB for the property:

    public ObservableCollection<string> SelectedChannels
    {
        get { return (ObservableCollection<string>)GetValue(SelectedChannelsProperty); }
        set { SetValue(SelectedChannelsProperty, value); }
    }

    public static readonly DependencyProperty SelectedChannelsProperty =
        DependencyProperty.Register("SelectedChannels", typeof(ObservableCollection<string>), typeof(ChannelSelector), new PropertyMetadata(new ObservableCollection<string>()));
1
How exactly do you update SelectedChannels?Sinatr
@Sinatr .Add()/.Remove() which "should" trigger the update, correct?Wobbles
@Sinatr I known the CollectionChanged event is firing because I hooked it and added a console dump and that looks good.Wobbles
CollectionChanged won't trigger that Binding.Clemens
I'd think what since you are binding to Text the binding is ignoring the INotifyCollectionChanged. You would have to go with standard procedure (subscribing to event).Sinatr

1 Answers

1
votes

One possibility to achieve wanted is to wrap converter logic into reusable behavior.

Here is one, it will work as your converter is supposed, but only with TextBlock.Text:

public static class Behaviors
{
    public static ObservableCollection<string> GetTest(DependencyObject obj) => (ObservableCollection<string>)obj.GetValue(TestProperty);
    public static void SetTest(DependencyObject obj, ObservableCollection<string> value) => obj.SetValue(TestProperty, value);

    public static readonly DependencyProperty TestProperty =
        DependencyProperty.RegisterAttached("Test", typeof(ObservableCollection<string>), typeof(Behaviors), new PropertyMetadata(null, (d, e) =>
        {
            var textBlock = d as TextBlock;
            var collection = e.NewValue as ObservableCollection<string>;
            collection.CollectionChanged += (s, a) => 
            {
                // put logic here
                textBlock.Text = ... ;
            };
        }));
}

Use it like this:

<TextBlock local:Behaviors.Test="{Binding ...}" />

TODO: add null checks, unsubscribing (may lead to memory leakages if binding to persistent ViewModel properties), proper naming...