Есть ли способ преобразовать членов коллекции, используемых в качестве источника данных?

В WPF вы можете использовать преобразователь IValueConverter или IMultiValueConverter для преобразования привязанного к данным значения от, скажем, от int до Color.

У меня есть набор объектов Model, которые я хотел бы преобразовать в их представления ViewModel, но в этом случае

<ListBox ItemsSource="{Binding ModelItems, 
     Converter={StaticResource ModelToViewModelConverter}" />

конвертер будет записан для преобразования всей коллекции ModelItems сразу.

Я хочу преобразовать элементы коллекции отдельно, есть ли способ сделать это?

Ответ 1

Вы не можете установить конвертер в самой коллекции, потому что он получит коллекцию в качестве входной информации. У вас есть два варианта:

  • Убедитесь, что ваш конвертер также может работать с коллекциями (IEnumerable).
  • Используйте конвертер в шаблоне элемента.

Если вы хотите использовать второй подход, используйте следующее:

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

Если вам не нужна специальная таблица данных, вы можете пропустить атрибут ContentTemplate.

Ответ 2

Да, вы можете. Он действует так же, как и с IValueConverter. Вы просто обрабатываете параметр value для метода Convert как коллекцию.

Вот пример конвертера для коллекции:

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();
    }
}

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

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

в набор целых чисел, соответствующий значению строки.

И вот соответствующий XAML (loc - это ссылка на текущую сборку, где находится преобразователь):

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

Если вы хотите сделать двустороннюю привязку, вам нужно также реализовать преобразование. Из опыта работы с MVVM я предлагаю использовать что-то вроде шаблона Factory для преобразования из модели в ViewModel и обратно.

Ответ 3

Вот еще один пример. Я использую MVVM Caliburn Micro. MyObjects - это список перечислений в моем случае.

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