Click here to Skip to main content
15,868,164 members
Home / Discussions / WPF
   

WPF

 
GeneralRe: (beginner) There must be a better way (TextBlock properties) Pin
Maximilien26-Jan-22 9:10
Maximilien26-Jan-22 9:10 
QuestionConverting a byte[] to a ImageSource means huge memory leak Pin
Starwer24-Jan-22 11:42
Starwer24-Jan-22 11:42 
AnswerRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Gerry Schmitz24-Jan-22 16:15
mveGerry Schmitz24-Jan-22 16:15 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Starwer24-Jan-22 19:58
Starwer24-Jan-22 19:58 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Gerry Schmitz24-Jan-22 21:26
mveGerry Schmitz24-Jan-22 21:26 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Starwer25-Jan-22 7:56
Starwer25-Jan-22 7:56 
AnswerRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Richard Deeming25-Jan-22 21:51
mveRichard Deeming25-Jan-22 21:51 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Starwer26-Jan-22 9:10
Starwer26-Jan-22 9:10 
Hi Richard,

Thanks a lot for this very complete answer.

I've removed the finalizer and implemented the IDisposable as you suggested. I like the DisposableObservableCollection proposal. It looks very neat this way.

Unfortunatly this doesn't solve the problem. The leak is just as bad as before, with Image/BitmapImage and MemoryStream never being freed. It has probabably something to do with the fact that the MemoryStream.Dispose() doesn't do anything like explain on this page.

In the end the code looked like this:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Toy
{


	internal class ToyItem : INotifyPropertyChanged, IDisposable
    {
        #region Boilerplate INotifyPropertyChanged

        protected void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChanged?.Invoke(this, e);
        }

        public void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler? PropertyChanged;

        #endregion

        public void Dispose()
        {
            if (Data is BitmapImage image)
            {
                image.StreamSource.Dispose();
            }

            Data = null;
        }

        /// <summary>
		/// Build an image from Picture bytes
		/// </summary>
		/// <param name="imageData">Picture as array of bytes</param>
		/// <returns>Pictures as BitmapImage</returns>
		public static ImageSource? BitmapFromRaw(byte[]? imageData)
		{
			if (imageData == null) return null;
			var image = new BitmapImage();
            var mem = new MemoryStream(imageData, false);
			//mem.Position = 0;
			image.BeginInit();
			//image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
			//image.CacheOption = BitmapCacheOption.None;
			//image.UriSource = null;
			image.StreamSource = mem;
			image.EndInit();
            //mem.Close();
            //mem.Dispose();
            image.Freeze();
 
            return image;
		}

		public ImageSource? Data
        {
            get { return _Data; }
            set
            {
                if (value != _Data)
                {
                    _Data = value;
                    OnPropertyChanged();
                }
            }
        }
        private ImageSource? _Data;
        
        public ToyItem ()
        {
            Data = BitmapFromRaw(Properties.Resources.pexels_jonathan_faria_8581946);
            //Data = new BitmapImage(new Uri(@"E:\Downloads\pexels-jonathan-faria-8581946.jpg"));
        }

    }


    public class DisposableObservableCollection<T> : ObservableCollection<T>, IDisposable
    where T : IDisposable
    {
        public DisposableObservableCollection(List<T> list) : base(list)
        {
        }

        public DisposableObservableCollection(IEnumerable<T> collection) : base(collection)
        {
        }

        public DisposableObservableCollection() : base ()
        {
        }

        protected override void SetItem(int index, T item)
        {
            T oldItem = this[index];
            base.SetItem(index, item);
            oldItem?.Dispose();
        }

        protected override void RemoveItem(int index)
        {
            T item = this[index];
            base.RemoveItem(index);
            item?.Dispose();
        }

        protected override void ClearItems()
        {
            List<T> itemsToDispose = Items.Where(i => i != null).ToList();
            base.ClearItems();
            foreach (T item in itemsToDispose)
            {
                item.Dispose();
            }
        }


        public void Dispose()
        {
            ClearItems();
        }

    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        DisposableObservableCollection<ToyItem> ToyList = new DisposableObservableCollection<ToyItem>();

        int Counter = 0;

        public MainWindow()
        {
            InitializeComponent();

            wxToy.DataContext = ToyList;
            wxButton.Content = Counter;
        }

        private void gcButton_Click(object sender, RoutedEventArgs e)
        {
            GC.Collect();
        }

        private void wxButton_Click(object sender, RoutedEventArgs e)
        {
            wxButton.Content = ++Counter;

            //foreach (var item in ToyList)
            //{
            //    item.Data = null;
            //}

            ToyList.Clear();

            for (int i = 0; i < 5; i++)
            {
                ToyList.Add(new ToyItem());
            }
        }
    }

}

GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Gerry Schmitz27-Jan-22 6:33
mveGerry Schmitz27-Jan-22 6:33 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Starwer27-Jan-22 20:29
Starwer27-Jan-22 20:29 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
lmoelleb3-Feb-22 4:58
lmoelleb3-Feb-22 4:58 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Starwer5-Feb-22 0:28
Starwer5-Feb-22 0:28 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
lmoelleb6-Feb-22 3:27
lmoelleb6-Feb-22 3:27 
AnswerRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Starwer30-Jan-22 5:04
Starwer30-Jan-22 5:04 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Gerry Schmitz30-Jan-22 5:23
mveGerry Schmitz30-Jan-22 5:23 
GeneralRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Starwer30-Jan-22 7:45
Starwer30-Jan-22 7:45 
SuggestionRe: Converting a byte[] to a ImageSource means huge memory leak Pin
Richard Deeming30-Jan-22 21:52
mveRichard Deeming30-Jan-22 21:52 
Question(MahApp) not using style for control Pin
Super Lloyd19-Jan-22 23:07
Super Lloyd19-Jan-22 23:07 
AnswerRe: (MahApp) not using style for control Pin
Super Lloyd19-Jan-22 23:08
Super Lloyd19-Jan-22 23:08 
QuestionMarkupExtension, resource files and visual studio designer Pin
Super Lloyd16-Jan-22 6:40
Super Lloyd16-Jan-22 6:40 
QuestionTextBox Bound To Decimal - Can't Type Decimal Pin
Kevin Marois28-Dec-21 8:29
professionalKevin Marois28-Dec-21 8:29 
AnswerRe: TextBox Bound To Decimal - Can't Type Decimal Pin
Mycroft Holmes28-Dec-21 10:05
professionalMycroft Holmes28-Dec-21 10:05 
GeneralRe: TextBox Bound To Decimal - Can't Type Decimal Pin
Kevin Marois28-Dec-21 10:25
professionalKevin Marois28-Dec-21 10:25 
GeneralRe: TextBox Bound To Decimal - Can't Type Decimal Pin
Super Lloyd16-Jan-22 6:45
Super Lloyd16-Jan-22 6:45 
GeneralRe: TextBox Bound To Decimal - Can't Type Decimal Pin
Mycroft Holmes16-Jan-22 10:55
professionalMycroft Holmes16-Jan-22 10:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.