如何将转换器应用于ObservableCollection的每个项目?

时间:2014-03-23 16:31:21

标签: c# wpf mvvm

我正在使用C#和.NET 4.5来创建MVVM桌面应用程序。我有一组已包含在ObservableCollection<MyEntryClass>中的视图模型条目。

我需要使用第三方控件来显示数据。此控件要求将条目转换为自己的条目类。他们使用XAML和IValueConverter提供了如何执行此操作的示例。归结为...Items="{Binding Path=The.Source, Converter={StaticResource CustomDataConverter}}...和一个大致如下所示的转换器:

public class CustomDataConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        IEnumerable<CustomItem> dataContext = value as IEnumerable<CustomItem>;
        ObservableCollection<OutputItem> items = new ObservableCollection<OutputItem>();
        foreach (CustomItem customItem in dataContext)
        {
            OutputItemitem =
                new OutputItem
                {
                    // ... some value transfers ...
                };
            items.Add(item);
        }
        return items;
    }

虽然这适用于控件的初始化,但它会破坏&#34;观察链&#34;控件和绑定中指定的ObservableCollection之间 - 只是因为自定义转换器创建自己的项列表。有没有办法更改绑定指令,以便不为整个源集合调用转换器一次,而是为每个集合元素调用一次?如果没有,有什么替代策略来处理这种情况?

(在上面的示例中,我省略了一些代码,它们将事件处理程序注册到源对象的PropertyChanged事件并更新目标对象。各个项属性的更新工作正常,它&# 39; s只是未处理的列表更新。)


编辑:有问题的第三方控件是来自GanttChartDataGridGantt Chart Light Library

2 个答案:

答案 0 :(得分:3)

如果此第三方控件提供此类可能性,您可以尝试在ItemTemplate中使用转换器。使用标准的WPF控件,它应该是这样的:

<ListBox ItemsSource="{Binding Path=The.Source}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <ContentPresenter Content="{Binding Converter={StaticResource CustomDataConverter}}" 
                    ContentTemplate="{StaticResource MyOptionalDataTemplate}"/>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

但实现这一目标的最简单方法可能是绑定包含OutputItems的集合......

答案 1 :(得分:0)

另一种方法可能是忘记在XAML代码中使用转换器并在ViewModel中进行转换。

您发布的转换器没有ConvertBack方法,因此我猜测您的第三部分控件所需的ObservableCollection<OutputItem>列表是只读的,这意味着从XAML到C#不会发生任何修改 - 正如大家所想的那样使用Grafic Chart库。

因此,您可以拥有2个属性,一个私有包含您将根据您的业务逻辑在ViewModel中更新的自定义对象,然后将一个公共属性绑定到您的第三个部分UserControl:

private ObservableCollection<OutputItem> myPrivateData 
{ 
   get; 
   set; 
}

private ObservableCollection<CustomItem> DataToPlotOnGant 
{ 
   get; 
   set; 
}

然后,您可以在私人收藏的CollectionChanged事件中进行转换:

this.myPrivateData.CollectionChanged += (s, e) =>
            {
                // do convertion stuff here
            };

并选择更新DataToPlotOnGant列表,只修改私有集合中更改的项目 - 更有效 - 或者每次像转换器那样创建新集合时都会创建。{/ p>