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的動畫效果過渡下。

感謝您的閱讀。代碼和測試圖片請點擊這里下載。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM