【发布时间】:2014-02-05 12:59:50
【问题描述】:
我正在尝试将项目(图像)添加到 ListBox,最好使用 WrapPanel 类型的布局。很简单。
我遇到的问题是,当我将 ListBox.ItemsPanel 模板定义为使用包装面板时,加载图像所花费的时间变得难以忍受。我目前正在添加大约 70 张图片,但我希望它能够支持数千张。
如果我不自定义列表框,加载速度会非常快。我在下面的 XAML 中提到了我要更改的部分。
我不明白的是
- 为什么看似很小的 xaml 更改会导致应用阻塞
-
我如何仍然可以获得具有不错性能的 wrappanel 类型布局。
<Grid> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Button Grid.Row=0 Name="ImageButton" Click="ImageButton_Click">GET IMAGES</Button> <ListBox Grid.Row="1" Name="ImageCollection" ScrollViewer.HorizontalScrollBarVisibility="Disabled"> <!-- Items added to list panel using Wrap Panel Template. --> <!-- By removing the below, things go pretty fast --> <!-- When the ListBox.ItemsPanel uses a wrappanel as below, loading up the images is SLOW. If I delete the below, loading is FAST, but isn't what I want. --> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel/> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> </Grid>
我的代码如下所示。我在这里没有更改任何内容,只是将其包含为信息。
public AsyncGet()
{
InitializeComponent();
}
private List<String> images = new List<string>(
Directory.GetFiles(@"C:\Users\me\Pictures\wallpapers")
);
private void ImageButton_Click(object sender, RoutedEventArgs e)
{
foreach (string s in images)
{
Image image = new Image();
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(s);
bi.EndInit();
image.Source = bi;
image.Height = 200;
image.Width = 200;
ImageCollection.Items.Add(image);
}
}
编辑
在尝试了一些我不太满意的 VirtualWrapPanel 实现之后,我决定坚持使用 WrapPanel。我做了一些似乎使主线程保持响应的事情:
- 保持 BitMapImage 解码尺寸和图像尺寸为 200
- 通过为每个项目添加默认图像开始加载。预期路径存储在 Images 标记中。
- 遍历每一项更新源,使用 async/await 生成 bitmapImage。
我不知道我正在按照预期的方式使用 async/await。但它似乎允许 UI 保持响应。图像被循环,最终所有默认值都被替换,它可能需要比其他方式更长的时间,但我更喜欢仍然接受用户输入的能力。
我希望我能找到一种方法来对它进行数据绑定,我可以稍后再试。
private List<String> images = new List<string>(
Directory.GetFiles(@"C:\Users\me\Pictures\wallpapers")
);
private Image defaultImage;
public AsyncGet()
{
InitializeComponent();
DataContext = this;
defaultImage = new Image();
defaultImage.Source = MakeBitmapImage( @"C:\Users\me\Pictures\MeowShawn_Lynch.jpg");
defaultImage.Height = 200;
defaultImage.Width = 200;
}
private async void ImageButton_Click(object sender, RoutedEventArgs e)
{
ImageCollection.Items.Clear();
foreach(string s in images)
{
Image image = new Image();
image.Source = defaultImage.Source;
image.Height = defaultImage.Height;
image.Width = defaultImage.Width;
ImageCollection.Items.Add(image);
image.Tag = s;
}
foreach (Image image in ImageCollection.Items)
{
string path = image.Tag.ToString();
Task<BitmapImage> task = new Task<BitmapImage>(() => MakeBitmapImage(path, true));
task.Start();
image.Source = await task;
}
}
private BitmapImage MakeBitmapImage(string path, Boolean freeze = false)
{
BitmapImage bi = new BitmapImage();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.BeginInit();
bi.UriSource = new Uri(path);
bi.DecodePixelHeight = 200;
bi.EndInit();
if (freeze)
{
bi.Freeze();
}
return bi;
}
【问题讨论】: