zoukankan      html  css  js  c++  java
  • WPF中加载高分辨率图片性能优化

    在最近的项目中,遇到一个关于WPF中同时加载多张图片时,内存占用非常高的问题。

    问题背景:

    在一个ListView中同时加载多张图片,注意:我们需要加载的图片分辨率非常高。

    代码:

    XAML:

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            
            <Button Content="Load" Width="100" Height="35" Margin="0,10" Click="Button_Click"/>
            
            <ListView Grid.Row="1" x:Name="lvImages">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <Image Source="{Binding ImageSource}" MaxWidth="800"/>
                    </DataTemplate>
                </ListView.ItemTemplate>
    
                <ListView.Template>
                    <ControlTemplate>
                        <Grid>
                            <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden">
                                <ItemsPresenter />
                            </ScrollViewer>
                        </Grid>
                    </ControlTemplate>
                </ListView.Template>
    
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel IsItemsHost="True" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizing="True"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
            </ListView>
        </Grid>

    C#:

        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                lvImages.Items.Clear();
    
                // Image folder location: D:Pics
    
                string[] files = System.IO.Directory.GetFiles(@"D:Pics");
    
                List<ImageSourceModel> models = new List<ImageSourceModel>();
    
                foreach(var path in files)
                {
                    BitmapImage image = new BitmapImage();
    
                    image.BeginInit();
    
                    image.UriSource = new System.Uri(path);
    
                    image.EndInit();
    
                    image.Freeze();
    
                    models.Add(new ImageSourceModel() { ImageSource = image });
                }
    
                lvImages.ItemsSource = models;
            }
        }
    
        public class ImageSourceModel
        {
            public ImageSource ImageSource { get; set; }
        }

    内存占用情况(此时只加载了20张图片,内存占用>1G):

    优化方案:

    1. 初始加载时,只加载部分图片并显示。当ScrollViewer滚动到底部时,再加载一部分。关于这个方案,可以参考 WPF MVVM模式下实现ListView下拉显示更多内容

    但是这并不能解决最终内存占用过高的情况。

    2. 给图片设置DecodePixelWidth属性,

        BitmapImage image = new BitmapImage();
    
        image.BeginInit();
    
        image.UriSource = new System.Uri(path);
    
        image.DecodePixelWidth = 800;
    
        image.EndInit();
    
        image.Freeze();
    
        models.Add(new ImageSourceModel() { ImageSource = image });

    此时的内存占用如图

    内存降低的非常显著,此时同样多的图片内存占用只有40M左右。

    最终我们可以把优化方案1和优化方案2结合起来。这样在加载多张图片时不会出现卡顿的现象。另外从用户体验的角度我们可以在图片显示出来前,先用一个Loading的动画效果过渡下。

    感谢您的阅读。代码和测试图片请点击这里下载。

  • 相关阅读:
    【转】sublime text 2中Emmet插件8个常用的技巧
    程序猿崛起3——这一次,我用行动说话
    《Effective Java》学习笔记——积累和激励
    程序猿崛起2——互联网时代下的新潮流和新活法
    【非技术】做好属于自己的作品,然后让世界所有人都记住你
    【非技术】实现理想的第一步就是做自己
    【原创】程序猿崛起
    人生苦短,我用python——当我在玩python的时候我玩些什么
    一个新人如何学习在大型系统中添加新功能和Debug
    一个应届毕业生入职30天后的工作总结——作息
  • 原文地址:https://www.cnblogs.com/yang-fei/p/4931406.html
Copyright © 2011-2022 走看看