Is there any way to convert the members of a collection used as an ItemsSource?

Here is another example. I'm using MVVM Caliburn Micro. MyObjects is a list of enums in my case.

<ListBox x:Name="MyObjects">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding ., Converter={StaticResource MyConverter}}"/>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

You cannot set the converter on the collection itself, because it would get the collection as input. You have two choices:

  1. Make sure your converter can also deal with collections (IEnumerable).
  2. Use the converter within the item template.

If you want to use the second approach, then use something like this:

<ListBox ItemsSource="{Binding ModelItems}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <ContentPresenter Content="{Binding Converter={StaticResource ModelToViewModelConverter}}" 
                        ContentTemplate="{StaticResource MyOptionalDataTemplate}"/>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

If you don't need a custom datatemplate, then you can skip the ContentTemplate attribute.


Yes you can. It is acting the same as with the IValueConverter. You simply treat the value parameter for the Convert method as a collection.

Here is an example of Converter for a collection:

public class DataConvert : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ObservableCollection<int> convertible = null;
        var result = value as ObservableCollection<string>;

        if (result != null)
        {
            convertible = new ObservableCollection<int>();
            foreach (var item in result)
            {
                if (item == "first")
                {
                    convertible.Add(1);
                }
                else if (item == "second")
                {
                    convertible.Add(2);
                }
                else if (item == "third")
                {
                    convertible.Add(3);
                }
            }
        }

        return convertible;
    }

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

In this case is just a proof of concept, but I think it should show the idea very well. The Converter converts from a simple collection of strings like this:

ModelItems = new ObservableCollection<string>();
        ModelItems.Add("third");
        ModelItems.Add("first");
        ModelItems.Add("second");

into a collection of integers corresponding to the string meaning.

And here is the corresponding XAML (loc is the reference of the current assembly where is the converter):

<Window.Resources>
    <loc:DataConvert x:Key="DataConverter"/>
</Window.Resources>
<Grid x:Name="MainGrid">
    <ListBox ItemsSource="{Binding ModelItems, Converter={StaticResource DataConverter}}"/>
</Grid>

If you want to make a two way binding, you have to implement also the convert back. From the experience of working with MVVM, i suggest to use something like the Factory Pattern to transform from Model in ViewModel and backwards.

Tags:

Wpf