Question

Please see Update at bottom of post

I'm writing a WPF app using .Net 4.5

I have a ListBox displaying movie info, the xaml is shown below.

<ListBox Margin="10, 5, 10, 10"
             ItemsSource="{Binding SearchResponse.Results}"
             HorizontalAlignment="Stretch"
             VerticalAlignment="Stretch">
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <EventSetter Event="MouseDoubleClick"
                             Handler="SearchResult_OnMouseDoubleClick">
                </EventSetter>
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Border BorderBrush="#3e3e42"
                        BorderThickness="1"
                        CornerRadius="5"
                        Background="#242424"
                        Padding="10">
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding ThumbnailPath}"
                               Width="{Binding RelativeSource={RelativeSource FindAncestor,
                                AncestorType={x:Type Window}},
                                Path=DataContext.ThumbnailWidth}"
                               Height="{Binding RelativeSource={RelativeSource FindAncestor,
                                AncestorType={x:Type Window}},
                                Path=DataContext.ThumbnailHeight}"
                               Margin="0,0,10,0" />
                        <StackPanel TextBlock.FontFamily="Segoe WP"
                                    TextBlock.FontSize="14"
                                    TextBlock.Foreground="WhiteSmoke"
                                    Width="300">
                            <TextBlock Text="{Binding Title}"
                                       TextTrimming="CharacterEllipsis" />
                            <TextBlock Text="{Binding Description}"
                                       TextTrimming="CharacterEllipsis"
                                       TextWrapping="Wrap"/>
                            <TextBlock Text="{Binding Path}"
                                       TextTrimming="CharacterEllipsis"/>
                        </StackPanel>
                    </StackPanel>
                </Border>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

Every thumbnail (Image) in the list will have the same width and height (either small, medium or large). For the window I have SizeToContent=Width so the window will resize itself when the thumbnail size is changed.

The problem is this: When I scroll the ListBox using the mouse wheel the ListBox width changes seemingly randomly and causes the window to increase in width. If I scroll using the scroll bar up and down buttons this doesn't happen.

I've debugged the ActualWidth of all of the elements in the ListBox item data template (text blocks, stack panels, border, etc.) and they all stay at the expected fixed width yet debugging the width of the listbox itself shows that it changes width randomly.

Here are two screenshots. The first shows the correct layout and the second shows the layout after scrolling the ListBox with the mouse wheel.

Correct layout

After scrolling, listbox gets wider!

So, why does the ListBox ActualWidth change when the items contained within do not?

Update: Some further investigation suggests that this behaviour is being caused by the fact that the images I am using for the thumbnail are larger than the thumbnail display size and are resized by the image control. It appears that the listbox is (sometimes) resized according to the original image size rather than the smaller resized image.

Anyone have any suggestions to overcome this?

Was it helpful?

Solution

I managed to fix this issue by writing a MultiValueConverter which takes in an image filepath and a pixel width (bound in xaml using a MultiBinding) and returns the correct size bitmap to display in the thumbnail Image control. The result is that the correct size image is used (and cached) so the ListBox width is constant.

This is the code for the converter:

public class PathToThumbnailConverter : IMultiValueConverter 
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var path = values[0] as string;
        var decodeWidth = (int)values[1];

        if (!string.IsNullOrEmpty(path))
        {
            var info = new FileInfo(path);

            if (info.Exists && info.Length > 0)
            {
                var bi = new BitmapImage();

                bi.BeginInit();
                bi.DecodePixelWidth = decodeWidth;
                bi.CacheOption=BitmapCacheOption.OnLoad;
                bi.UriSource=new Uri(info.FullName);
                bi.EndInit();

                return bi;
            }
        }
        return null;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

And here is the xaml for declaring it:

<Window.Resources>
    <valueConverters:PathToThumbnailConverter x:Key="ThumbConverter"/>
</Window.Resources>

And using it:

<Image.Source>
   <MultiBinding Converter="{StaticResource ThumbConverter}">
    <Binding Path="ThumbnailPath"/>
    <Binding RelativeSource="{RelativeSource FindAncestor,
        AncestorType={x:Type Window}}" Path="DataContext.ThumbnailWidth"/>
   </MultiBinding>
</Image.Source>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top