Что ж, хорошая новость в том, что я знаю, почему SelectedCode
не устанавливается, когда я не использую конвертер значений.Плохая новость в том, что у меня все еще есть что-то загадочное, но проблема немного подтолкнула вверх по пищевой цепочке, и у меня есть обходной путь.из дополнительных функций, которые стали возможными благодаря тому, что он знает, какие элементы в нем.Свойства SelectedCode
и CodeLookupTable
строго типизированы и скрывают базовые свойства SelectedItem
и ItemsSource
, которых нет.(Кстати, именно поэтому это пользовательский элемент управления, а не подкласс ComboBox
; я не хочу, чтобы эти свойства были видны, потому что много вещей может произойти, если они установлены неправильно, ни одно из них не является хорошим.)
Вот что происходит.Это мой отладочный вывод, когда конвертер значений подключен (число - это хэш-код элемента управления, потому что у меня есть куча из них, которые все рисуются одновременно при инициализации программы):
14626603: OnCodeLookupTablePropertyChanged
CodeLookupTable property set to Proceedings.Model.CodeLookupTable
box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
14626603: OnSelectedCodePropertyChanged:
SelectedCode property set to Unlicensed Driver [VC12500(A)]
box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
Это ожидаемое поведение.Свойство CodeLookupTable
установлено, поэтому установка SelectedCode
для одного из элементов в этой коллекции правильно устанавливает SelectedItem
для базового ComboBox
.
Но без преобразователя значений мы получаем это:
16143157: OnSelectedCodePropertyChanged:
SelectedCode property set to Unlicensed Driver [VC12500(A)]
box.MainComboBox.ItemsSource =
16143157: OnCodeLookupTablePropertyChanged
CodeLookupTable property set to Proceedings.Model.CodeLookupTable
box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
Здесь свойство SelectedCode
устанавливается до , свойство CodeLookupTable
имеет значение.Поэтому, когда метод пытается установить SelectedItem
на базовый ComboBox
, ничего не происходит, потому что ItemsSource
равен нулю.
А вот корень проблемы.Я по глупости предположил, что порядок, в котором привязки обновляют свою цель, совпадает с порядком, в котором они объявлены в XAML.(Одна из причин, по которой я выразил привязки в виде элементов вместо атрибутов, заключается в том, что порядок элементов в документе XML является детерминированным, а порядок атрибутов - нет. Не то чтобы я об этом не думал.)видимо не тот случай.
Я также предположил, может быть, немного менее глупо, что порядок, в котором привязки обновляют свою цель, не зависит от того, подключены ли к ним преобразователи значений.Ну, это так.Интересно, от чего еще это зависит?
К счастью, у меня есть способ обойти это.Поскольку мой CodeLookup
объект содержит ссылку на CodeLookupTable
, я могу сделать так, чтобы установщик SelectedCode
установил свойство CodeLookupTable
(и, следовательно, ItemsSource
) в первую очередь, если оно еще не было установлено.Это позволит решить эту проблему, не привязывая к привязке фальшивый преобразователь значений, и надеюсь, что поведение привязок никогда не изменится.
Редактировать
Вот чтообъявления собственности выглядят так:
#region SelectedCode
public static readonly DependencyProperty SelectedCodeProperty = DependencyProperty.Register(
"SelectedCode", typeof(CodeLookup), typeof(CodeLookupBox),
new FrameworkPropertyMetadata(OnSelectedCodePropertyChanged));
private static void OnSelectedCodePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
CodeLookupBox box = (CodeLookupBox)source;
CodeLookup code = e.NewValue as CodeLookup;
// this right here is the fix to the original problem:
if (box.CodeLookupTable == null && code != null)
{
box.CodeLookupTable = code.Table;
}
box.MainComboBox.SelectedItem = e.NewValue;
}
public CodeLookup SelectedCode
{
get { return GetValue(SelectedCodeProperty) as CodeLookup; }
set { SetValue(SelectedCodeProperty, value); }
}
#endregion
#region CodeLookupTable
public static readonly DependencyProperty CodeLookupTableProperty = DependencyProperty.Register(
"CodeLookupTable", typeof(CodeLookupTable), typeof(CodeLookupBox),
new FrameworkPropertyMetadata(OnCodeLookupTablePropertyChanged));
private static void OnCodeLookupTablePropertyChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
CodeLookupBox box = (CodeLookupBox)source;
CodeLookupTable table = (CodeLookupTable)e.NewValue;
box.ViewSource = new CollectionViewSource { Source = table.Codes };
box.View = box.ViewSource.View;
box.MainComboBox.ItemsSource = box.View;
}
public CodeLookupTable CodeLookupTable
{
get { return GetValue(CodeLookupTableProperty) as CodeLookupTable; }
set { SetValue(CodeLookupTableProperty, value); }
}
#endregion