사진 브라우저 WPF 앱-성능 향상
저는 개인 프로젝트로 WPF 사진 브라우저 앱에서 작업하고 있습니다. 나는 매번 전체 이미지를 읽을 때 썸네일 처리에 대한 현재 전략이 좋지 않다는 것을 알고 있습니다. 이것은 몇 개 이상의 이미지가있는 폴더를 탐색 할 때 나타납니다. 누군가가 코드의이 측면을 개선 할 수있는 변경 사항을 제안 할 수 있다면 매우 유용 할 것입니다.
코드의 슬림화 된 버전은 다음과 같습니다. 이것은 폴더를 가져와 그 안에있는 이미지의 썸네일과 이름을 표시합니다. (전체 앱에는 이미지에 대한 다양한 작업을 수행하는 버튼도 있습니다.)
MainWindow.xaml.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;
namespace PhotoBrowser
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
private string _folder;
public string Folder
{
get => _folder;
set
{
_folder = value;
if (Directory.Exists(_folder))
{
var filesInFolder = Directory.EnumerateFiles(_folder);
var files_ = new ObservableCollection<FileItem>();
foreach (string file in filesInFolder)
{
files_.Add(new FileItem(file, false));
}
Files = files_;
}
else
{
Files = new ObservableCollection<FileItem>();
}
OnPropertyChanged();
}
}
private ObservableCollection<FileItem> _files;
public ObservableCollection<FileItem> Files
{
get => _files;
set
{
_files = value;
OnPropertyChanged();
}
}
public MainWindowViewModel() { }
}
}
MainWindow.xaml
<Window x:Class="PhotoBrowser.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:PhotoBrowser"
mc:Ignorable="d"
Title="Photo Browser" Height="800" Width="800" MinHeight="300" MinWidth="400">
<Grid HorizontalAlignment="Stretch" Height="Auto" Margin="10,10,10,10" VerticalAlignment="Stretch" Width="Auto" ShowGridLines="False">
<Grid.RowDefinitions>
<RowDefinition Height="35"/>
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="Folder"
Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
<TextBox x:Name="Folder"
Text="{Binding Folder, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="1"
HorizontalAlignment="Stretch" Height="25" TextWrapping="NoWrap" Margin="5,5,5,5"
VerticalAlignment="Center"/>
<ListBox x:Name="FilesInCurrentFolder"
Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Stretch"
BorderBrush="Black" Height="Auto" Width="772" SelectionMode="Extended"
ItemsSource="{Binding Files, UpdateSourceTrigger=PropertyChanged}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Thumbnail}" Width="100" Height="100"/>
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected, UpdateSourceTrigger=PropertyChanged}" />
</Style>
</ListBox.Resources>
</ListBox>
</Grid>
</Window>
FileItem.cs
using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows.Media.Imaging;
namespace PhotoBrowser
{
public class FileItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
private string _fileName;
public string FileName
{
get => _fileName;
set
{
_fileName = value;
OnPropertyChanged();
OnPropertyChanged("Name");
}
}
private string _name;
public string Name
{
get => Path.GetFileName(_fileName);
set
{
_name = value;
_fileName = Path.Combine(Path.GetDirectoryName(_fileName), value);
OnPropertyChanged();
OnPropertyChanged("FileName");
}
}
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
_isSelected = value;
OnPropertyChanged();
}
}
private BitmapSource _thumbnail;
public BitmapSource Thumbnail
{
get => _thumbnail;
set
{
_thumbnail = value;
OnPropertyChanged();
}
}
public FileItem(string fileName)
{
this.FileName = fileName;
GetThumbnail();
}
public FileItem(string fileName, bool isSelected) : this(fileName)
{
this.IsSelected = isSelected;
}
public void GetThumbnail()
{
Image image = new Bitmap(FileName);
image = image.GetThumbnailImage(100, 100, () => false, IntPtr.Zero);
Thumbnail = new BitmapImage(new Uri(FileName));
}
}
}
답변
일부 속성 설정자가 너무 많은 일을하고 있다고 생각합니다. 예를 들어 MainWindow
의 Folder
속성 setter는 폴더 이름을 설정하지 않습니다뿐만 아니라 해당 폴더 내의 모든 파일을 열거하고 수집하는 시간이 걸립니다. 이것은 단일 책임 원칙 과 아마도 최소 경악 의 원칙에 위배 됩니다. 나는 그런 응용 프로그램을 사용했고 내가 원하는 것은 폴더로 이동하는 것이었지만 각 클릭은 폴더에서 강제로 읽는 것처럼 보입니다. 요컨대, 폴더 설정은 폴더 만 설정해야하며 해당 폴더의 파일을 열거하는 것은 별도의 작업이어야합니다.
일부 비동기 호출을 구현하고 스트리밍을 유지하면 성능이 향상 될 수 있습니다. 함께 스트리밍 EnumerateFiles
하지만 목록에 추가합니다. 이로 인해 성능이 저하 될 수 있습니다. 파일을 읽어야한다고 생각하는 정확한 순간을 조사하고 그 순간까지 파일 읽기를 지연합니다.
와 관련된 모든 비동기 메서드를 읽어야합니다 BitMap
. 이 게시물 은 C #을 사용하여 비트 맵을 비동기 적으로로드하는 방법을 찾습니다 . 백그라운드 작업을 사용하여 파일을 열거하거나 축소판을로드하는 것을 고려할 수 있습니다.