View Issue Details

IDProjectCategoryView StatusLast Update
0002188NoesisGUIC# SDKpublic2021-11-16 13:08
ReporterDavidYawCSpeed Assigned Tosfernandez  
PrioritynormalSeveritymajorReproducibilityalways
Status feedbackResolutionopen 
Product Version3.1.1 
Summary0002188: Data Bindings to virtualized list items don't update
DescriptionI have a list control, and I'm binding to several properties of the items in that list. When the UI elements are removed due to list virtualization, The bound properties don't update, even when they should.

In particular, I'm binding to ListViewItem.IsSelected. When the selected item is scrolled off of the top of the screen, it gets removed because list virtualization is enabled. When a new item is selected, the binding to the newly-selected item updates, but the binding to the newly-deselected item doesn't update. When I then look at the bound properties, it looks like multiple items are selected at the same time.

Comparing against 3.0.12, it looks like the selected ListViewItem isn't removed until after it has been de-selected. Therefore the binding updates, and the bound property has the correct value.
Steps To Reproduce- I have a ListView. Via one of the default styles, VirtualizingPanel.VirtualizationMode=Recycling.
- I am binding ListViewItem.IsSelected to a property on the item's data context.
<Style x:Key="ListMenuListViewItemStyle" TargetType="{x:Type ListViewItem}">
  <Setter Property="IsSelected" Value="{Binding IsSelectedItem}"/>

- For demo purposes, I have debug prints on the Loaded & Unloaded events.
<DataTemplate x:Key="SimpleMenuItemDataTemplateKey">
  <Border x:Name="editBorder" BorderBrush="Transparent" Loaded="Border_OnLoaded" Unloaded="Border_OnUnloaded">

private void Border_OnLoaded(object sender, RoutedEventArgs args)
{
  FrameworkElement fe = sender as FrameworkElement;
  ListViewItem lvi = (ListViewItem)fe.TemplatedParent.TemplatedParent;

  ListMenuItem menuItem = (args.Source as FrameworkElement)?.DataContext as ListMenuItem;
  String name = (menuItem as SimpleListMenuItem).Name;
  string lmiselected = menuItem.IsSelectedItem.ToString();
  String selected = lvi.IsSelected.ToString();
  logger.Error($"OnLoaded(): {name}, ListViewItem.IsSelected = {selected}, DataContextItem.IsSelectedItem = {lmiselected}");
}

// Similar for Unloaded. 

- For demo purposes, I have a debug print on the setter of the IsSelectedItem property.
private bool _isSelectedItem;
public bool IsSelectedItem
{
  get => _isSelectedItem;
  set
  {
    logger.Error($"IsSelectedItem.set: {this.ToString()}, DataContextItem.IsSelectedItem = {value}");

    _isSelectedItem = value;
    RaisePropertyChangedEvent("IsSelectedItem");
  }
}


----------------------------

I am testing this using our language selection screen. the languages are on the list in alphabetical order by language ID.

Using 3.1.1:

On entering the screen, the visible items are loaded, and we explicitly re-select the first item in the list, cs-CZ.

2021-11-15 10:17:51.6579|ERROR|IsSelectedItem.set: cs-CZ, DataContextItem.IsSelectedItem = True
2021-11-15 10:17:51.7131|ERROR|OnLoaded(): cs-CZ, ListViewItem.IsSelected = True, DataContextItem.IsSelectedItem = True
2021-11-15 10:17:51.7131|ERROR|OnLoaded(): de-DE, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:17:51.7131|ERROR|OnLoaded(): en-US, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:17:51.7131|ERROR|OnLoaded(): es-ES, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:17:51.7131|ERROR|OnLoaded(): fi-FI, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:17:51.7131|ERROR|OnLoaded(): fr-FR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:17:51.7729|ERROR|IsSelectedItem.set: cs-CZ, DataContextItem.IsSelectedItem = False
2021-11-15 10:17:51.7729|ERROR|IsSelectedItem.set: cs-CZ, DataContextItem.IsSelectedItem = True


If I select another language that's currently on the screen, the data bindings for both the old & new selected items update.

2021-11-15 10:17:54.0138|ERROR|IsSelectedItem.set: en-US, DataContextItem.IsSelectedItem = True
2021-11-15 10:17:54.0146|ERROR|IsSelectedItem.set: cs-CZ, DataContextItem.IsSelectedItem = False


Then back to the original selection.

2021-11-15 10:17:57.9800|ERROR|IsSelectedItem.set: cs-CZ, DataContextItem.IsSelectedItem = True
2021-11-15 10:17:57.9800|ERROR|IsSelectedItem.set: en-US, DataContextItem.IsSelectedItem = False


Then, scroll down to the bottom of the list. Since the list is virtualizing, we get a bunch of unloaded & loaded events, including for the currently selected item.

2021-11-15 10:18:00.1216|ERROR|OnUnloaded(): cs-CZ, ListViewItem.IsSelected = True, DataContextItem.IsSelectedItem = True  <----- Selected item unloaded!
2021-11-15 10:18:00.1240|ERROR|OnLoaded(): hu-HU, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.1240|ERROR|OnLoaded(): it-IT, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.1734|ERROR|OnUnloaded(): es-ES, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.1734|ERROR|OnUnloaded(): en-US, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.1734|ERROR|OnUnloaded(): de-DE, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.1765|ERROR|OnLoaded(): ja-JP, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.1765|ERROR|OnLoaded(): ko-KR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.1765|ERROR|OnLoaded(): nl-BE, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2168|ERROR|OnUnloaded(): hu-HU, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2168|ERROR|OnUnloaded(): fr-FR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2168|ERROR|OnUnloaded(): fi-FI, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2192|ERROR|OnLoaded(): pl-PL, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2192|ERROR|OnLoaded(): pt-BR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2192|ERROR|OnLoaded(): ru-RU, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2499|ERROR|OnUnloaded(): ja-JP, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2508|ERROR|OnUnloaded(): it-IT, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2508|ERROR|OnLoaded(): sv-SE, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2508|ERROR|OnLoaded(): tr-TR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2821|ERROR|OnUnloaded(): nl-BE, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2829|ERROR|OnUnloaded(): ko-KR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 10:18:00.2829|ERROR|OnLoaded(): zh-CN, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False


Now that the selected item is unloaded, clicking an item at the bottom of the list updates the new selected item's binding, but not the old selected item's binding.

2021-11-15 10:18:02.0472|ERROR|IsSelectedItem.set: tr-TR, DataContextItem.IsSelectedItem = True
// No IsSelectedItem = False for cs-CZ!


Using 3.0.12:

The load and 'select something on the same screen' steps are the same.

Scrolling down: Unloaded and Loaded events, but the selected item is never unloaded. (cs-CZ isn't in this list.)

2021-11-15 15:37:21.1415|ERROR|OnLoaded(): hu-HU, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.1576|ERROR|OnLoaded(): it-IT, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.1908|ERROR|OnUnloaded(): de-DE, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.1908|ERROR|OnLoaded(): ja-JP, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.2071|ERROR|OnUnloaded(): en-US, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.2071|ERROR|OnLoaded(): ko-KR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.2411|ERROR|OnUnloaded(): es-ES, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.2411|ERROR|OnLoaded(): nl-BE, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.2764|ERROR|OnUnloaded(): fi-FI, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.2764|ERROR|OnLoaded(): pl-PL, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.6595|ERROR|OnUnloaded(): fr-FR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.6652|ERROR|OnLoaded(): pt-BR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.7076|ERROR|OnUnloaded(): hu-HU, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.7097|ERROR|OnLoaded(): ru-RU, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.7269|ERROR|OnUnloaded(): it-IT, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.7269|ERROR|OnLoaded(): sv-SE, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.7407|ERROR|OnUnloaded(): ja-JP, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.7407|ERROR|OnLoaded(): tr-TR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.7767|ERROR|OnUnloaded(): ko-KR, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.7767|ERROR|OnLoaded(): zh-CN, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:21.7987|ERROR|OnUnloaded(): nl-BE, ListViewItem.IsSelected = False, DataContextItem.IsSelectedItem = False


Then, when clicking on an item at the bottom of the list, the data binding updates for the old selected item, then it is removed because of the virtualization.

2021-11-15 15:37:30.9940|ERROR|IsSelectedItem.set: cs-CZ, DataContextItem.IsSelectedItem = False
2021-11-15 15:37:30.9940|ERROR|IsSelectedItem.set: tr-TR, DataContextItem.IsSelectedItem = True
2021-11-15 15:37:30.9940|ERROR|OnUnloaded(): cs-CZ, ListViewItem.IsSelected= False, DataContextItem.IsSelectedItem = False


With 3.0.12, our list of list items only has one where IsSelectedItem is true, while 3.1.1 has multiple where this is true, because the data binding didn't update.
TagsNo tags attached.
PlatformAny

Activities

sfernandez

sfernandez

2021-11-16 13:08

manager   ~0007572

As I mentioned in #2168 this behavior is consistent with WPF.
The solution is to disable virtualization for that list, or delegate the selection to the SelectedItem property instead of using the container IsSelected property.

Issue History

Date Modified Username Field Change
2021-11-15 22:46 DavidYawCSpeed New Issue
2021-11-16 13:06 sfernandez Assigned To => sfernandez
2021-11-16 13:06 sfernandez Status new => assigned
2021-11-16 13:08 sfernandez Status assigned => feedback
2021-11-16 13:08 sfernandez Note Added: 0007572