使用c# /WPF显示缩略图网格
本文关键字:略图 网格 显示 WPF 使用 | 更新日期: 2023-09-27 18:17:05
在我的c#/WPF应用程序中,我想从图像文件的目录树中显示图像缩略图的网格(目前是.bmp的,但最终是其他格式)。在未来,我可能希望允许用户点击缩略图查看更大的版本,或者将鼠标悬停在缩略图上查看一些技术细节,但现在我想做的就是显示缩略图。
图像的数量是不可预测的,我的指示是,如果屏幕上的图像太多,就启用滚动(而不是,比如说,缩小缩略图)。
我有一个递归例程来遍历树并识别要显示的文件… private bool WalkTree(String sRoot)
{
string sDirectoryName;
string sFileName;
int iDirectoryCount = 0;
DirectoryInfo DirInfo;
DirInfo = new DirectoryInfo(sRoot);
// Get a list of all the files in this directory.
foreach (FileInfo fi in DirInfo.GetFiles("*.bmp"))
{
sFileName = fi.Name;
// DO SOMETHING WITH FILE FOUND HERE
}
// Now get a list of all the subfolders in this directory.
foreach (DirectoryInfo di in DirInfo.GetDirectories())
{
sDirectoryName = di.Name;
WalkTree(sRoot + "''" + sDirectoryName); //recurse!!
iDirectoryCount++;
}
return true;
} // End WalkTree
那么有什么好的方法可以做到这一点呢?我应该使用什么XAML控件来放置所有这些?一个网格?我能在其中添加行,并在递归发现更多文件时滚动吗?或者我应该遍历树两次—一次获取计数并配置页面中的行和列,第二次实际显示缩略图?还是我想错了?
我觉得这个问题在过去已经解决了很多次了,一定有一个规范的设计模式,但是我找不到。
注释描述了如何做布局部分。这是相对容易的,使用什么解决方案取决于实际布局。UniformGrid
很好。在这里使用ItemsControl
就足够了:
<ItemsControl ItemsSource="{Binding Images}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<ScrollViewer>
<UniformGrid />
</ScrollViewer>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Width="100" Height="100" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
问题是:什么是Images
,你绑定ItemsSource
的属性?您所拥有的是具有文件名的字符串列表,您需要的是ImageSource
s的集合。没有办法将图像加载到内存中。如果你不想让你的应用程序在大量的图片中消耗大量的内存,那么你仍然需要高效地完成它。一个选项是将图像缩放为缩略图。其次,当你缩放图像时,这是一个很好的机会来裁剪它们,以获得固定的长宽比,使网格看起来很漂亮。
Images需要是BitmapImage
的集合,以便与Image
控件的ImageSource
属性绑定:
public ObservableCollection<BitmapImage> Images { get; set; }
这基本上就是// DO SOMETHING WITH FILE FOUND HERE
:
var image = CreateBitmap(path);
var width = image.PixelWidth;
var height = image.PixelHeight;
// Crop image (cut the side which is too long)
var expectedHeightAtCurrentWidth = width*4.0/3.0;
var expectedWidthAtCurrentHeight = height*3.0/4.0;
var newWidth = Math.Min(expectedWidthAtCurrentHeight, width);
var newHeight = Math.Min(expectedHeightAtCurrentWidth, height);
var croppedImage = CropImage(image, (int)newWidth, (int)newHeight);
// Scale to with of 100px
var ratio= 100.0 / newWidth;
var scaledImage = ScaleImage(croppedImage, ratio);
Images.Add(scaledImage);
使用以下函数来创建,缩放和裁剪图像:
private static BitmapImage CreateBitmap(string path)
{
var bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(path);
bi.EndInit();
return bi;
}
private BitmapImage ScaleImage(BitmapImage original, double scale)
{
var scaledBitmapSource = new TransformedBitmap();
scaledBitmapSource.BeginInit();
scaledBitmapSource.Source = original;
scaledBitmapSource.Transform = new ScaleTransform(scale, scale);
scaledBitmapSource.EndInit();
return BitmapSourceToBitmap(scaledBitmapSource);
}
private BitmapImage CropImage(BitmapImage original, int width, int height)
{
var deltaWidth = original.PixelWidth - width;
var deltaHeight = original.PixelHeight - height;
var marginX = deltaWidth/2;
var marginY = deltaHeight/2;
var rectangle = new Int32Rect(marginX, marginY, width, height);
var croppedBitmap = new CroppedBitmap(original, rectangle);
return BitmapSourceToBitmap(croppedBitmap);
}
private BitmapImage BitmapSourceToBitmap(BitmapSource source)
{
var encoder = new PngBitmapEncoder();
var memoryStream = new MemoryStream();
var image = new BitmapImage();
encoder.Frames.Add(BitmapFrame.Create(source));
encoder.Save(memoryStream);
image.BeginInit();
image.StreamSource = new MemoryStream(memoryStream.ToArray());
image.EndInit();
memoryStream.Close();
return image;
}