5

Noted: Universal Windows Platform (aka Windows 10 App, not WPF)

I have about 80 image files that need to be displayed on a listview inside a page. When user go back to previous page, i need to dispose the Image control so I can delete these images.

The problem is binding directly to image uri lock the image files, and it's not released when going back

I'm using MVVMLight

Some code:

public class FileNameToFullUriConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        string ori = value.ToString();
        string file = ori.Split('/').Last();
        string img = file.Split('.')[0] + ".png";
        img = "ms-appdata:///local/" + StaticClass.ImageFolder + "/" + img;

        return img;

    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        return null;
    }
}

and XAML

<DataTemplate>
    <Grid>
        <Image x:Name="Image2"
               Grid.Column="1"
               HorizontalAlignment="Left"
               Source="{Binding Page2.Page.file,
               Converter={StaticResource FileNameToFullUriConverter},
               Mode=OneWay}"
               Stretch="UniformToFill" />
    </Grid>
</DataTemplate>

I've tried:

  • Set the list to null

  • Clear the list (by calling ListViewName.Clear() )

  • Call Cleanup in ViewModelLocator

What's working, but cannot apply: In ViewModel, I added another property with type of

ObservableCollection<BitmapImage>

, then binding the ListView to this collection. By using this way, all the image will be loaded into RAM, no lock on file, but it's cause a serious problem: Consume too much RAM. My app from using binding with URI took about 100 MB RAM to 900 MB RAM by binding directly to BitmapImage. Also, the time it took to load into the page take longer, since it has to read and load all the image file into RAM before the list finish rendered.

So, how to dispose Image Control in Windows 10?

PS: this image control: Image Class in MSDN

Hunter Tran
  • 13,257
  • 2
  • 14
  • 23
  • Can you try opening these images as StorageFile-s without locking the files itself and then use them instead of BitmapImage in your solution? – Alex Sorokoletov Apr 29 '16 at 10:09

3 Answers3

1

You can maintain a list of your Image controls in the code behind of the page. When the app go back, you can set Source property to null for each images :

<DataTemplate>
    <Grid>
        <Image Loaded="Image_Loaded" />
    </Grid>
</DataTemplate>

In code behind :

private List<Image> _images = new List<Image>();

private void Image_Loaded(object sender, RoutedEventArgs e)
{
    _images.Add(sender as Image);
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    base.OnNavigatedFrom(e);
    foreach(var img in _images)
    {
        img.Source = null;
    }
}

All locks will be released.

t.ouvre
  • 2,856
  • 1
  • 11
  • 17
  • Sorry, this is what i've tried. It's worked, but cause memory leak. App from using 100 MB RAM rise up to 900 MB RAM. – Hunter Tran Dec 23 '15 at 09:52
  • I'm thinking of making a custom Image Control, and dispose the image inside that control rather than use the default one – Hunter Tran Dec 23 '15 at 09:53
0

I'm not really familiar with the image control. It seems to me that the bitmap image must be Disposed before you can delete the file. The problem is that the bitmapImage does not have a Dispose funciton.

I saw other people here in stack overflow asking how to actively Dispose the image. I guess you'll have to do the same.

See: How to dispose bitmapsource

Delete a bitmapsource file

Community
  • 1
  • 1
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
0

I had the same problem. I have used a workaround which I'm not sure that this is the best way or not. I have added a method to removed deleted items and call the method each time the app starts or the list gets refreshed.

private ObservableCollection<BitmapImage> _items; // your collection which is bound to ListView

// deleting images of removed items
private async Task DeleteUnusedImages()
{
    try
    {
        var folder = await ApplicationData.Current.LocalFolder.GetFolderAsync("folderName");
        var files = await folder.GetFilesAsync(); // getting all files inside that folder

        foreach (var file in files)
        {
            // checking if the image still exist in the collection or got removed
            // if removed then remove it from the local folder too.
            if (!_items.Any(i => i.ImageName.Contains(file.Name)))
            {
                await file.DeleteAsync(StorageDeleteOption.PermanentDelete);
            }
        }
    }
    catch (Exception ex)
    {

    }
}

The problem is when you delete an item from the collection that bound to the ListView, the ListView does not release the item until several refreshes. After deleting an item I have tried to manually deleting it by going to "LocalState" folder of the app but it says that it's used by the app and cannot be deleted.

Sapan Ghafuri
  • 545
  • 3
  • 13