Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF ListBox Template bindings update only on scrolling

I have the following ListBox with the ContentControl as DataTemplate:

<ListBox x:Name="lstActionConfigs" ItemsSource="{Binding Path=AllActionConfigList}" SelectedItem="{Binding Path=ListSelectedItem, Mode=TwoWay}" HorizontalContentAlignment="Stretch" Grid.Row="3" Margin="0,0,0,5">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="{x:Type helper:ItemDetails}">
            <ContentControl Template="{StaticResource ResourceKey=actionDetailsListItemTemplate}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                <i:Interaction.Behaviors>
                    <behaviours:BringIntoViewBehaviour CustomIsSelected="{Binding Path=IsSelected, Mode=TwoWay}"/>
                </i:Interaction.Behaviors>
            </ContentControl>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Each bounded instance has 'IsSelected' property which notify the UI on changes via INotifyPropertyChanged:

public bool IsSelected
{
    get { return isSelected; }
    set
    {
        isSelected = value;
        notify("IsSelected");
    }
}

I built a custom behavior that brings into view the elements that changed it's IsSelectedProperty to true, as the follows:

public class BringIntoViewBehaviour : Behavior<FrameworkElement>
{
    public bool CustomIsSelected
    {
        get { return (bool)GetValue(CustomIsSelectedProperty); }
        set { SetValue(CustomIsSelectedProperty, value); }
    }
    public static readonly DependencyProperty CustomIsSelectedProperty =
            DependencyProperty.Register("CustomIsSelected", typeof(bool), typeof(BringIntoViewBehaviour), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(customIsSelectedPropertyChanged_Callback)));

    private static void customIsSelectedPropertyChanged_Callback(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        BringIntoViewBehaviour thisControl = o as BringIntoViewBehaviour;

        if (thisControl == null)
            return;

        bringIntoView(thisControl);
    }
}

This item is not presented this moment on the UI as it located at the bottom of the list (there is a scroll bar).

I updated the IsSelected property with true value.

However, the customIsSelectedPropertyChanged_Callback method should be executed as we updated it's bounded property.

But, in practice, this method is invoked only when this item is presented on UI when moving the scroll bar down to it.

like image 364
Jacob Avatar asked Oct 26 '25 06:10

Jacob


1 Answers

The reason most likely is UI virtualization. ListBox items host is by default VirtualizingStackPanel. It will not generate items which are out of view now, so when you set IsSelected on your model, your DataTemplate together with your behaviour are not created yet. Only when you scroll down, control is created together with behaviour from data template, and after it is bound CustomIsSelectedProperty is set to true, so your callback is called.

To verify this assumption you can disable UI virtualization for your ListBox and see if that resolves the problem.

like image 80
Evk Avatar answered Oct 29 '25 07:10

Evk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!