Привязка ComboBox.SelectedItem в Silverlight (подробнее)

Относится к моему предыдущему вопросу: Привязка ComboBox.SelectedItem в Silverlight

У меня есть ComboBox, привязанный так:

<ComboBox x:Name="PART_CommentaryList" 
    HorizontalAlignment="Left" 
    Margin="3" 
    ItemsSource="{Binding Path=CurrentVideo.Commentaries}" 
    SelectedItem="{Binding Path=CurrentCommentary, Mode=TwoWay}">

И свойства CurrentVideo, и CurrentCommentary регулярно меняются. Через несколько раз я получаю такую ​​ошибку:

Category: ManagedRuntimeError       
Message: System.ArgumentException: Value does not fall within the expected
   range.
   at MS.Internal.XcpImports.MethodEx(IntPtr ptr, String name, 
       CValue[] cvData)
   at MS.Internal.XcpImports.MethodPack(IntPtr objectPtr, String methodName, 
       Object[] rawData)
   at MS.Internal.XcpImports.UIElement_TransformToVisual(UIElement element, 
       UIElement visual)
   at System.Windows.UIElement.TransformToVisual(UIElement visual)
   at System.Windows.Controls.Primitives.Selector.IsOnCurrentPage(
       Int32 index, Rect& itemsHostRect, Rect& listBoxItemRect)
   at System.Windows.Controls.Primitives.Selector.ScrollIntoView(
       Int32 index)
   at System.Windows.Controls.Primitives.Selector.SetFocusedItem(
       Int32 index, Boolean scrollIntoView)
   at System.Windows.Controls.ComboBox.PrepareContainerForItemOverride(
       DependencyObject element, Object item)
   at System.Windows.Controls.ItemsControl.UpdateContainerForItem(
       Int32 index)
   at System.Windows.Controls.ItemsControl.RecreateVisualChildren()
   at System.Windows.Controls.ItemsControl.RecreateVisualChildren(
       IntPtr unmanagedObj)

Мне это кажется ошибкой ComboBox. Я могу проверить, что CurrentVideo изменяется до CurrentCommentary, поэтому выбранный элемент всегда должен быть элементом, который находится в списке.

В связи с этим мне действительно не нужен Mode = TwoWay, потому что, когда ItemsSource изменяется, SelectedItem временно принимает значение null, которое возвращается в мою модель, чего я на самом деле не хочу. Но в противном случае привязка вообще не работает (что похоже на еще одну ошибку).


person Josh Santangelo    schedule 14.05.2009    source источник
comment
Вы проверяете, есть ли CurrentCommentary в списке CurrentVideo.Commentaries, потому что в противном случае вы получите эту ошибку.   -  person Jeffrey Lott    schedule 14.05.2009
comment
Я внедрил преобразователь в оба связанных свойства, чтобы проверить, действительно ли выбранный элемент находится в источнике элементов. Проблема, похоже, заключается в следующем: ItemsSource изменяется. Это изменение приводит к тому, что SelectedItem становится нулевым. SelectedCommentary изменяется на null, потому что это двусторонняя привязка. SelectedCommentary устанавливается приложением на правильное значение, это значение определенно находится в ItemsSource. Произошла ошибка. Если режим привязки не является двусторонним, ошибки не возникает, но правильный элемент никогда не выбирается.   -  person Josh Santangelo    schedule 14.05.2009


Ответы (4)


Это ошибка в элементе управления ComboBox, связанная с изменяющимся указателем привязки ItemsSource. Решение, которое я нашел, заключается в следующем:

1) Всегда привязывайте ItemsSource к наблюдаемой коллекции и никогда не сбрасывайте указатель OC.

<ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyItem}" />

Плохой:

MyList = new ObservableCollection();

Хорошо:

MyList.Clear();
MyList.AddRange(...);

2) Установите MyItem = null перед очисткой MyList

В вашем случае вы меняете ссылку на Список всякий раз, когда меняете CurrentView. Следовательно, если SelectedItem не равно null, есть короткий момент времени, когда ItemsSource сбрасывается, внутренние компоненты ComboBox пытаются найти объект SelectedItem в новом ItemsSource, но старого объекта там нет.

person markti    schedule 21.05.2009
comment
Спасибо за это предложение @markti. У меня была такая же ошибка в приложении Магазина Windows 8.1, и она заставляла меня лечиться. Интересен тот факт, что я просто использовал тот же подход, который отлично работает в другом представлении, подход, когда ItemsSource моего ComboBox привязан к List ‹›, а не к ObservableCollection. Я лучше вернусь и поменяю его там тоже. - person Eddie; 30.11.2016

Спасибо за предложения выше. В моей ситуации я могу выбрать «ядерный вариант», то есть - всякий раз, когда необходимо изменить выбранный элемент, я полностью уничтожаю ComboBox, создаю новый и соответствующим образом устанавливаю его SelectedItem.

Смешно, но работает.

person Josh Santangelo    schedule 14.05.2009

Combobox - довольно глючный элемент управления SL :-(.

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

http://blogs.msdn.com/mikehillberg/archive/2009/03/26/implementing-selectedvalue-with-the-silverlight-combobox.aspx

HTH Браулио

person Braulio    schedule 14.05.2009
comment
Интересный пост, но, похоже, это не имеет отношения к моей проблеме. Однако я узнал о DisplayMemberPath. Раньше я устанавливал новый DataTemplate только для отображения свойства элемента. - person Josh Santangelo; 15.05.2009

Некоторое время назад у меня была такая же проблема, и, насколько я могу судить, это ошибка в ComboBox, когда при изменении ItemSource возникает проблема с макетом и плохая прокрутка.

Существует обходной путь путем вызова ComboBox.UpdateLayout между установкой ItemSource и SelectedItem.

Некоторое время назад я писал об этой проблеме на странице Gotcha при привязке ComboBox в Silverlight.

Мне еще предстоит проверить, существует ли проблема в бета-версии Silverlight 3.

person Nigel Sampson    schedule 14.05.2009
comment
Использование UpdateLayout - хороший подход, но я попробовал и все равно получил ту же ошибку. Я получаю это при установке SelectedItem в коде или через привязку. - person Josh Santangelo; 15.05.2009
comment
В примере в вашем блоге вы привязываетесь к свойству, где получатель динамически создает новый OC ‹T› при получении. Это изменит указатель, используемый привязкой ItemsSource при каждой его оценке. Более стабильным подходом было бы объявить OC ‹T› и добавить в него элементы. Кроме того, динамически создавая OC ‹T›, нет смысла даже использовать OC ‹T›, вы также можете использовать список ‹T›. - person markti; 21.05.2009
comment
Согласен, в конце концов я перешел на такую ​​модель, однако это все еще ошибка, на которую нужно обращать внимание при изменении источников предметов. - person Nigel Sampson; 22.05.2009