У меня была такая же проблема с отключением ComboBox при изменении их DataContext. У меня есть относительно простое решение, которое использует класс, который я написал под названием «ComboBoxFixer». После внедрения вы можете решить эту проблему, просто заменив это:
<ComboBox ItemsSource="..." SelectedItem="..." />
с этим:
<ComboBox ItemsSource="..." my:ComboBoxFixer.SelectedItem="..." />
Объяснение проблемы
Причина, по которой ваши ComboBoxы появляются пустыми, заключается в том, что привязка SelectedItems оценивается, когда ItemsSource не установлен. Это можно исправить, отложив передачу данных в SelectedItems и обратно до тех пор, пока не будет завершено связывание всех других данных.
Как реализовать ComboBoxFixer
Мой класс ComboBoxFixer реализован с использованием общего класса синхронизатора свойств зависимостей, который я написал. Мой класс DependencyPropertySynchronizer имеет следующий интерфейс:
public class DependencyPropertySynchronizer
{
public DispatcherPriority Priority { get; set; }
public DependencyProperty AutoSyncProperty { get; set; }
public DependencyProperty Register(...
public DependencyProperty RegisterAttached(...
public DependencyPropertyKey RegisterReadOnly(...
public DependencyPropertyKey RegisterAttachedReadOnly(...
}
И обычно используется так:
public SomeClass : DependencyObject
{
static DependencyPropertySynchronizer sync =
new DependencyPropertySynchronizer
{
Priority = DispatcherPriority.ApplicationIdle
};
public static readonly DependencyProperty HappinessProperty =
sync.RegisterAttached("Happiness", typeof(int), typeof(SomeClass));
public static readonly DependencyProperty JoyProperty =
sync.RegisterAttached("Joy", typeof(int), typeof(SomeClass));
}
Приведенный выше код приведет к тому, что присоединенные свойства Happiness и Joy любого данного объекта останутся синхронизированными: всякий раз, когда установлено либо Happiness, либо Joy, для другого будет установлено значение DispatcherPriority.ApplicationIdle. DependencyPropertySynchronizer реализован с использованием скрытого вложенного свойства, в котором хранится последнее значение, установленное в любом свойстве, и координируется планирование обновлений. Вы также можете синхронизировать с существующим свойством, установив AutoSyncProperty.
Используя этот класс, мой класс ComboBoxFixer очень прост:
public class ComboBoxFixer : DependencyObject
{
static DependencyPropertySynchronizer sync =
new DependencyPropertySynchronizer
{
Priority = DispatcherPriority.ApplicationIdle,
AutoSyncProperty = Selector.SelectedItemProperty,
};
public static readonly DependencyProperty SelectedItemProperty =
sync.RegisterAttached("SelectedItem", typeof(object), typeof(ComboBoxFixer),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
});
public static object GetSelectedItem(... // normal attached property stuff
public static void SetSelectedItem(...
}
Как это работает
При каждом изменении my: ComboBoxFixer.SelectedItem синхронизатор обновляет Selector.SelectedItem с приоритетом ApplicationIdle или наоборот.
Поток данных:
ViewModel property
<- bound from ->
my:ComboBoxFixer.SelectedItem
<- synced with ->
ComboBox.SelectedItem
Дополнительные примечания
В определенных обстоятельствах, если вы на самом деле переключаете ItemsSource, возможно, для SelectedItem будет установлено значение null более недавно, чем правильное значение. Эту проблему можно решить, добавив функцию проверки в DependencyObjectSynchronizer, а затем используйте ее для игнорирования нулевых значений во время синхронизации.