[英]Displaying a grid of thumbnails with C#/WPF
在我的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
的一个匹配。 无法将图像加载到内存中。 如果您不希望您的应用在图像数量众多且数量庞大时消耗大量内存,那么您仍然需要高效地执行此操作。 一种选择是将图像缩放为缩略图。 其次,在缩放图像时,这是一个很好的机会来裁剪它们以获得固定的宽高比并使网格看起来很漂亮。
图像需要是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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.