Похоже, это вызвано конвертером. ObservableCollection реализует INotifyCollectionChanged, который уведомляет пользовательский интерфейс об изменении коллекции (Добавить / Удалить / Заменить / Переместить / Сбросить). Это все изменения в коллекции, а не ее содержимое, поэтому обновления, которые вы видели раньше, были связаны с тем, что ваш класс реализовал INotifyPropertyChanged. Поскольку MultiCoverter возвращает новую коллекцию новых объектов, данные в исходных коллекциях не будут распространяться на них, так как нет привязок к исходным объектам, которые они могли бы уведомить.
Первое, что я хотел бы предложить, - взглянуть на элемент CompositeCollection и посмотреть, подойдет ли он вашим потребностям.
Вместо того, чтобы устанавливать ItemsSource таким, какой вы есть, вы могли бы поддерживать исходные объекты примерно так:
<ctrls:DataGrid.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Targets}" />
<CollectionContainer Collection="{Binding Actuals}" />
</CompositeCollection>
</ctrls:DataGrid.ItemsSource>
(я предполагаю, что «не реагирует на какие-либо изменения в базовых данных» относится к изменению значений, а не к изменению коллекции, если я ошибаюсь, дайте мне знать, и я более подробно на это посмотрю). )
Редактировать дополнения
В случае, если это не работает, альтернативой является написание нового класса, который обернет как целевые, так и фактические коллекции. Затем с помощью этих оболочек можно создать одну коллекцию ObservableCollection. На самом деле это лучший метод по сравнению с использованием ValueConverter или CompositeCollection. В любом случае вы потеряете часть функциональности, которая была изначально. Используя преобразователь значений для воссоздания коллекции, она больше не привязывается напрямую к исходным объектам, поэтому уведомление о свойстве может быть потеряно. При использовании CompositeCollection у вас больше нет отдельной коллекции, которую можно перебирать или изменять с помощью добавления / удаления / перемещения и т. Д., Поскольку он должен знать, над какой коллекцией работать.
Этот тип функциональности обертывания может быть весьма полезен в WPF и является очень упрощенной версией ViewModel, являющейся частью шаблона проектирования M-V-VM. Его можно использовать, когда у вас нет доступа к базовым классам для добавления INotifyPropertyChanged или IDataErrorInfo, а также может помочь добавить дополнительные функции, такие как состояние и взаимодействие, к базовым моделям.
Вот краткий пример, демонстрирующий эту функциональность, когда оба наших начальных класса имеют одно и то же свойство Name и не реализуют INotifyPropertyChanged, который не разделяется между ними.
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Foo foo1 = new Foo { ID = 1, Name = "Foo1" };
Foo foo3 = new Foo { ID = 3, Name = "Foo3" };
Foo foo5 = new Foo { ID = 5, Name = "Foo5" };
Bar bar1 = new Bar { ID = 1, Name = "Bar1" };
Bar bar2 = new Bar { ID = 2, Name = "Bar2" };
Bar bar4 = new Bar { ID = 4, Name = "Bar4" };
ObservableCollection<FooBarViewModel> fooBar = new ObservableCollection<FooBarViewModel>();
fooBar.Add(new FooBarViewModel(foo1, bar1));
fooBar.Add(new FooBarViewModel(bar2));
fooBar.Add(new FooBarViewModel(foo3));
fooBar.Add(new FooBarViewModel(bar4));
fooBar.Add(new FooBarViewModel(foo5));
this.DataContext = fooBar;
}
}
public class Foo
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Bar
{
public int ID { get; set; }
public string Name { get; set; }
}
public class FooBarViewModel : INotifyPropertyChanged
{
public Foo WrappedFoo { get; private set; }
public Bar WrappedBar { get; private set; }
public int ID
{
get
{
if (WrappedFoo != null)
{ return WrappedFoo.ID; }
else if (WrappedBar != null)
{ return WrappedBar.ID; }
else
{ return -1; }
}
set
{
if (WrappedFoo != null)
{ WrappedFoo.ID = value; }
if (WrappedBar != null)
{ WrappedBar.ID = value; }
this.NotifyPropertyChanged("ID");
}
}
public string BarName
{
get
{
return WrappedBar.Name;
}
set
{
WrappedBar.Name = value;
this.NotifyPropertyChanged("BarName");
}
}
public string FooName
{
get
{
return WrappedFoo.Name;
}
set
{
WrappedFoo.Name = value;
this.NotifyPropertyChanged("FooName");
}
}
public FooBarViewModel(Foo foo)
: this(foo, null) { }
public FooBarViewModel(Bar bar)
: this(null, bar) { }
public FooBarViewModel(Foo foo, Bar bar)
{
WrappedFoo = foo;
WrappedBar = bar;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
А потом в окне:
<ListView ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="Foo Name" DisplayMemberBinding="{Binding FooName}"/>
<GridViewColumn Header="Bar Name" DisplayMemberBinding="{Binding BarName}"/>
</GridView>
</ListView.View>
</ListView>