Home > database >  WPF VirtualizingStackPanel not redrawing on horizontal resize
WPF VirtualizingStackPanel not redrawing on horizontal resize

Time:08-17

I have an ItemsControl with a vertical VirtualizingStackPanel that has items with wrapping TextBlocks. Horizontally resizing the parent container fails to re-draw the elements below a certain size, only redrawing once you've scrolled up/down. However above a certain size the redrawing happens correctly. This only seems to be an issue when Virtualization is enabled.

I've created a simple example which demonstrates the issue here...

<Window x:Class="WpfTesting.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfTesting"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance local:MainWindow}"
        Title="MainWindow" Height="450" Width="800">
    <ItemsControl ItemsSource="{Binding LongStrings}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border Margin="5" 
                        Padding="5"
                        Background="Gray"
                        BorderBrush="Black"
                        BorderThickness="2"
                        CornerRadius="8">
                    <TextBlock TextWrapping="Wrap"
                               Text="{Binding}"/>
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.Template>
            <ControlTemplate TargetType="ItemsControl">
                <ScrollViewer CanContentScroll="True"
                              Focusable="False">
                    <ItemsPresenter />
                </ScrollViewer>
            </ControlTemplate>
        </ItemsControl.Template>
    </ItemsControl>
</Window>

CodeBehind...

public partial class MainWindow : Window
{
    public List<string> LongStrings { get; }
    
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        LongStrings = Enumerable.Range(1, 20)
            .Select(_ => new string(Enumerable.Repeat('a', 1000).ToArray()))
            .ToList();
    }
}

CodePudding user response:

The problem seems to be CanContentScroll="True".

You may instead use a ListBox with disabled selection:

<ListBox ItemsSource="{Binding LongStrings}"
         ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="Focusable" Value="False"/>
            <Setter Property="IsHitTestVisible" Value="False"/>
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Border Margin="3" 
                    Padding="5"
                    Background="Gray"
                    BorderBrush="Black"
                    BorderThickness="2"
                    CornerRadius="8">
                <TextBlock TextWrapping="Wrap"
                           Text="{Binding}"/>
            </Border>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

CodePudding user response:

I feel a little silly that the solution is so simple but you can fix it relatively easily by binding the Width property of the Item you're displaying to the ActualWidth property of the VirtualizingStackPanel.

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Grid Width="{Binding ActualWidth, ElementName=StackPanel}">
            <Border Margin="5"
                    Padding="5"
                    Background="Gray"
                    BorderBrush="Black"
                    BorderThickness="2"
                    CornerRadius="8">
                <TextBlock TextWrapping="Wrap"
                           Text="{Binding}"/>
            </Border>
        </Grid>
    </DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <VirtualizingStackPanel x:Name="StackPanel"/>
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

Frankly I'm convinced that the rendering behaviour of the VirtualizingStackPanel is a bug given just how odd it is.

  • Related