silverlight - 当图像是 xaml 中的数据绑定(bind)时清除图像缓存(释放内存)

标签 silverlight windows-phone-7 xaml

根据 Stefan Wick 的博客,从图像中释放内存就像执行以下操作一样简单:

  BitmapImage bitmapImage = image.Source as BitmapImage;
  bitmapImage.UriSource = null;
  image.Source = null;

但是,如果我像这样在 Xaml 中使用数据绑定(bind),如何才能达到相同的效果?:

// 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;
         }
    }

在这种情况下,每次点击按钮都会消耗额外的内存,直到手机/模拟器崩溃。尽管清除了列表框的 ItemSource 属性,但图像并未从内存中释放。

最佳答案

BitmapCreateOptions Enumeration这样定义了BackgroundCreation枚举:

Causes a BitmapSource to be initialized as soon as it is declared. This option uses the image cache for previously used URIs. If an image is not in the image cache, the image will be downloaded and decoded on a separate background thread.

这让我认为,当您更改 UriSource 属性并处置旧图像时,不会通知处理位图下载的后台线程,并且该后台线程会继续下载图像。这样做可能是因为手机实现了自己的所有图像缓存(请注意 BitmapCreateOptions 枚举中存在“IgnoreImageCache”元素)。

这可能是罪魁祸首,但另一种可能性是列表框的虚拟化实际上并未发生。最常见的原因是列表中的项目没有明确定义为具有相同的高度。 ListBox 中的虚拟化在幕后使用 VirtualizingStackPanel,并要求每个项目具有相同的高度。如果任何项目的高度不同,则虚拟化行为将被取消。下面是一些可以帮助您确定是否为 virt 的代码。是否实际发生。虚拟化的另一件事是,目前您的图像在下载图像数据之前没有设定的高度。这意味着在下载图像之前,所有图像的高度均为 0 像素。如果所有图像的高度均为 0 像素,则意味着根据 virt,所有图像都“在 View 中”。按逻辑,他们都应该开始下载。

总而言之,请尝试以下操作:

  1. 将 CreateOptions 更改为不同的内容(或者根本不设置)
  2. 显式设置列表框中图像标签的高度。 (这是必须的)
  3. 使用以下代码查看是否为 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;
    }
}

将 XAML 更改为 Hook 绑定(bind)到 BoundImage 的 ImageURL 属性:

// 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>

关于silverlight - 当图像是 xaml 中的数据绑定(bind)时清除图像缓存(释放内存),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9473948/

相关文章:

silverlight - 动画路径填充 - Silverlight

.net - 将行颜色绑定(bind)到 MVVM 中的属性(取决于行中的数据)

c# - Windows Phone 7 - 加密的 SQLite

c# - 如何以编程方式提取 Windows Phone 的 LiveID?

c# - 为什么图像不在网格面板中自动调整大小?

Silverlight 项目 - 滑入和滑出面板 - 如何?

c# - 队列 ForEach 循环抛出 InvalidOperationException

c# - System.IO.FileNotFoundException : Could not load file or assembly 'Silvernium, 版本=1.0.4254.29979

c# - 单击文本 block 时隐藏同级列表框

c# - 对象的 ActualHeight 和 ActualWidth 始终为零