Silverlight 在xaml中绑定图像数据时清除图像缓存(释放内存)
根据Stefan Wick的博客,从图像中释放内存与执行以下操作一样简单:Silverlight 在xaml中绑定图像数据时清除图像缓存(释放内存),silverlight,windows-phone-7,xaml,Silverlight,Windows Phone 7,Xaml,根据Stefan Wick的博客,从图像中释放内存与执行以下操作一样简单: BitmapImage bitmapImage = image.Source as BitmapImage; bitmapImage.UriSource = null; image.Source = null; 但是,如果像这样在Xaml中使用数据绑定,如何实现相同的效果 // inside MainPage.xaml <Button Tap="GetImages">Get Images<
BitmapImage bitmapImage = image.Source as BitmapImage;
bitmapImage.UriSource = null;
image.Source = null;
但是,如果像这样在Xaml中使用数据绑定,如何实现相同的效果
// inside MainPage.xaml
<Button Tap="GetImages">Get Images</Button>
<ListBox ItemSource="{Binding Links}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- I am not binding to Image's Source directly, because I want to use the bitmap's 'Background creation' option and it's download progress event in the future -->
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
//inside MainPage.xaml.cs
public void GetImages(object sender, RoutedEventArgs e) {
(DataContext as ViewModel).GetMeSomeImages();
}
// inside ViewModel.cs
public void GetMeSomeImages() {
List<string> links = ThisMethodGetsLinks();
Links.Clear();
foreach(var link in links)
Links.Add(link);
}
ObservableCollection<string> _links;
public ObservableCollection<string> Links {
get {
if (_links == null)
_links = new ObservableCollection<string>();
return _links;
}
}
//MainPage.xaml内部
获取图像
//内部MainPage.xaml.cs
public void GetImages(对象发送方,RoutedEventArgs e){
(DataContext作为ViewModel);
}
//inside ViewModel.cs
public void GetMeSomeImages(){
列表链接=ThisMethodGetsLinks();
Links.Clear();
foreach(链接中的var链接)
链接。添加(链接);
}
可观测采集链接;
公共收集链接{
得到{
如果(_links==null)
_links=新的observeCollection();
返回链接;
}
}
在这种情况下,每次点击按钮都会消耗额外的内存,直到手机/模拟器崩溃。尽管清除了Listbox的ItemSource属性,图像仍不会从内存中释放。因此定义了BackgroundCreation枚举:
使BitmapSource在声明后立即初始化。此选项将图像缓存用于以前使用的URI。如果图像不在图像缓存中,图像将在单独的后台线程上下载和解码
这使我认为,当您更改UriSource属性并处理旧图像时,处理位图下载的后台线程不会得到通知,而该后台线程会继续下载图像。这可能是因为手机自己实现了对所有图像的缓存(请注意BitmapCreateOptions枚举中存在“IgnoreImageCache”元素)
这很可能是罪魁祸首,但是另一种可能性是ListBox的虚拟化实际上并没有发生。最常见的原因是列表中的项目没有明确定义为具有相同的高度。ListBox中的虚拟化在封面下使用VirtualzingStackPanel,并且要求每个项目都具有相同的高度。如果任何项目的高度不同,则虚拟化行为将被取消。下面是一些代码,可以帮助您确定virt是否正确。是否真的发生了。虚拟化的另一个特点是,在下载图像数据之前,当前图像没有设置的高度。这意味着在下载图像之前,所有图像的高度均为0像素。如果所有图像的高度均为0像素,则根据virt,这意味着所有图像都“在视图中”。逻辑上,他们都应该开始下载
总之,尝试以下几点:
using System.Diagnostics;
public class BoundImage
{
private string imageURL;
public static int TotalImagesRequested = 0;
public BoundImage(string url)
{
imageURL = url;
}
public string ImageURL
{
get
{
TotalImagesRequested++;
// Watch the output window and see if TotalImagesRequested is
// growing to a crazy high amount (if it is it will eventually
// reach the total Count of the _links variable. But your
// app may crash before that happens.
Debug.WriteLine("Images being requested: " + TotalImagesRequested);
return imageURL;
}
}
}
//inside MainPage.xaml.cs
public void GetImages(object sender, RoutedEventArgs e)
{
(DataContext as ViewModel).GetMeSomeImages();
}
// inside ViewModel.cs
public void GetMeSomeImages()
{
List<string> links = ThisMethodGetsLinks();
Links.Clear();
_links = new ObservableCollection<BoundImage>();
foreach(string link in links)
{
_links.Add(new BoundImage(link));
}
}
ObservableCollection<BoundImage> _links;
public ObservableCollection<BoundImage> Links
{
get
{
if (_links == null)
_links = new ObservableCollection<BoundImage>();
return _links;
}
set
{
_links = value;
}
}
// inside MainPage.xaml
<Button Tap="GetImages">Get Images</Button>
<ListBox ItemSource="{Binding Links}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- I am not binding to Image's Source directly, because I want to use the bitmap's 'Background creation' option and it's download progress event in the future -->
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding ImageURL}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
已更改用于公开链接的属性:
using System.Diagnostics;
public class BoundImage
{
private string imageURL;
public static int TotalImagesRequested = 0;
public BoundImage(string url)
{
imageURL = url;
}
public string ImageURL
{
get
{
TotalImagesRequested++;
// Watch the output window and see if TotalImagesRequested is
// growing to a crazy high amount (if it is it will eventually
// reach the total Count of the _links variable. But your
// app may crash before that happens.
Debug.WriteLine("Images being requested: " + TotalImagesRequested);
return imageURL;
}
}
}
//inside MainPage.xaml.cs
public void GetImages(object sender, RoutedEventArgs e)
{
(DataContext as ViewModel).GetMeSomeImages();
}
// inside ViewModel.cs
public void GetMeSomeImages()
{
List<string> links = ThisMethodGetsLinks();
Links.Clear();
_links = new ObservableCollection<BoundImage>();
foreach(string link in links)
{
_links.Add(new BoundImage(link));
}
}
ObservableCollection<BoundImage> _links;
public ObservableCollection<BoundImage> Links
{
get
{
if (_links == null)
_links = new ObservableCollection<BoundImage>();
return _links;
}
set
{
_links = value;
}
}
// inside MainPage.xaml
<Button Tap="GetImages">Get Images</Button>
<ListBox ItemSource="{Binding Links}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- I am not binding to Image's Source directly, because I want to use the bitmap's 'Background creation' option and it's download progress event in the future -->
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding ImageURL}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
//MainPage.xaml.cs内部
public void GetImages(对象发送方,RoutedEventArgs e)
{
(DataContext作为ViewModel);
}
//inside ViewModel.cs
public void GetMeSomeImages()
{
列表链接=ThisMethodGetsLinks();
Links.Clear();
_links=新的observeCollection();
foreach(链接中的字符串链接)
{
_添加(新的BoundImage(link));
}
}
可观测采集链接;
公共收集链接
{
得到
{
如果(_links==null)
_links=新的observeCollection();
返回链接;
}
设置
{
_链接=价值;
}
}
将XAML更改为钩住绑定到BoundImage的ImageURL属性:
using System.Diagnostics;
public class BoundImage
{
private string imageURL;
public static int TotalImagesRequested = 0;
public BoundImage(string url)
{
imageURL = url;
}
public string ImageURL
{
get
{
TotalImagesRequested++;
// Watch the output window and see if TotalImagesRequested is
// growing to a crazy high amount (if it is it will eventually
// reach the total Count of the _links variable. But your
// app may crash before that happens.
Debug.WriteLine("Images being requested: " + TotalImagesRequested);
return imageURL;
}
}
}
//inside MainPage.xaml.cs
public void GetImages(object sender, RoutedEventArgs e)
{
(DataContext as ViewModel).GetMeSomeImages();
}
// inside ViewModel.cs
public void GetMeSomeImages()
{
List<string> links = ThisMethodGetsLinks();
Links.Clear();
_links = new ObservableCollection<BoundImage>();
foreach(string link in links)
{
_links.Add(new BoundImage(link));
}
}
ObservableCollection<BoundImage> _links;
public ObservableCollection<BoundImage> Links
{
get
{
if (_links == null)
_links = new ObservableCollection<BoundImage>();
return _links;
}
set
{
_links = value;
}
}
// inside MainPage.xaml
<Button Tap="GetImages">Get Images</Button>
<ListBox ItemSource="{Binding Links}">
<ListBox.ItemTemplate>
<DataTemplate>
<!-- I am not binding to Image's Source directly, because I want to use the bitmap's 'Background creation' option and it's download progress event in the future -->
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding ImageURL}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
//MainPage.xaml内部
获取图像
您是如何尝试为列表框中的图像释放内存的?目前,在我的应用程序中,我绑定了这样一个图像,其中MyImage是我创建的位图图像,并存储在视图模型中的可观察集合中,但我需要手动启动后台线程并通过Webclient下载它。然后,一旦我请求新图像,我就“清除”Listbox的ItemSource设置为的ObservableCollection(通过将每个MyImage的URI源设置为null),它似乎可以降低内存,但比Xaml解决方案要详细得多。我一直在互联网上寻找基于Xaml的解决方案,但运气不好。