WPF:如何快速将大量大型图像加载到WrapPanel中?

6

我有大约45张相当大的图片(约为680x1000),需要加载到一个简单的用户控件(带填充的圆角背景、图像、文本块和2个侧矩形)中,然后在wrappanel中显示。虚拟化在这里不会真正起到帮助作用,因为这些图片在程序加载时都需要显示。

我知道在BitmapImage init内部可以设置decodepixel宽度,这确实有所帮助,但是我想加载所有图片的完整尺寸,因为我想能够通过滑块调整图像大小而不失去质量(这部分工作大多数情况下都很快)。 我知道一种可能性是将decodewidth设置为某个数字,该数字设置为最大可视大小可能有所帮助。

我尝试了在如何在后台加载图像?(第一个答案)中找到的多线程方法,但它导致程序加载时间变得非常长!

有什么想法吗?

当前加载代码:

BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
//bmp.DecodePixelWidth = 400;
bmp.UriSource = new Uri(file.FullName);
bmp.EndInit();
bmp.Freeze();
images.Add(bmp);

示例 XAML 代码:

        <Border x:Name="backBorder" Background="Black" Padding="2" Margin="3" CornerRadius="3,3,4,4" 
            BorderBrush="Black" BorderThickness="1"
            MouseEnter="backBorder_MouseEnter" MouseLeave="backBorder_MouseLeave" MouseLeftButtonUp="backBorder_MouseLeftButtonUp" >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="16" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="15" />
        </Grid.ColumnDefinitions>
        <Image x:Name="imageBox" Stretch="Fill" Width="{Binding Path=ImageWidth, ElementName=me}" Height="{Binding Path=ImageHeight, ElementName=me}" />
        <Border x:Name="backRatingBorder" Grid.Column="1" Margin="3,0,0,0" BorderBrush="Blue" Background="White" BorderThickness="1"/>
        <Border x:Name="frontRatingBorder" Grid.Column="1" Margin="3,0,0,0" BorderBrush="Blue" Background="LightBlue" BorderThickness="1" VerticalAlignment="Bottom" Height="50"/>
        <TextBlock x:Name="textBlock" Grid.Row="1" Grid.ColumnSpan="2" TextAlignment="Center" Background="Transparent" Foreground="White" FontFamily="Segoe UI" FontWeight="SemiBold" FontSize="12" />
   </Grid>
</Border>

更新:

我最终通过在单个后台工作线程中运行加载图像循环,使其更加响应。每次加载完图像后,都会调用Dispacher.Invoke来创建包装项。经过一段时间的试验,我成功地让它在与之前相同的时间内显示每个创建的项。

1个回答

1
如果您对整体性能满意,只是图片的加载速度较慢,您可以尝试这个多线程UI教程。我很容易就成功实现了它,但如果您正在循环加载所有图片,则在加载完所有图片之前不会更新视觉效果。然而,在此期间UI是响应的,因为所有加载都在单独的线程上进行。
另外,如果您正在循环加载所有图片,则可以尝试改进版的Windows Forms DoEvents方法(向下滚动到示例)。在加载每个图像后调用它,它将给UI一个机会来更新自己(处理用户交互等)。这是我在为我的项目加载地图瓦片时使用的方法,比第一种方法更容易。

1
我认为我的主要问题是将图像从磁盘加载到内存中。我不确定我是否真的能在这里修复任何东西,有吗?我将所有图像加载到列表中,然后使用对列表中的BitmapImages的引用生成所有包装项。我可以快速清除所有包装子项并重新创建它们,但加载本身需要多个秒钟。我尝试使用Parallel.For循环将图像加载到列表中,但它导致加载变得更慢,可能是由于异步磁盘访问。 - user380527

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接