DevExpress ImageSlider - VirtualMode nie zwalnia obrazka z pamięci i nie można go usunąć ze ścieżki

0

Witam.
Nie jest pewny, czy to na 100% ma głównie coś wspólnego ze sliderem od DevExpressów. Przykład, którym się posiłkowałem niestety nie spełnia tego co bym chciał, albo robię coś źle.

Wczytywanie obrazków


        public static LinkedList<ImageInfo> Load(List<string> images)
        {
            LinkedList<ImageInfo> list = new LinkedList<ImageInfo>();
            foreach (string filePath in images)
            {
                list.AddLast(new ImageInfo(filePath));
            }
            return list;
        }

Klasa elementu listy obrazków - zerżnięta żywcem z przykładu DevExpressowego

    public class ImageInfo : IDisposable
    {
        string filePath;
        Lazy<Image> image;

        public ImageInfo(string path)
        {
            filePath = path;
            image = new Lazy<Image>(() => Image.FromFile(filePath));
        }
        public string Path { get { return filePath; } }
        public Image Image
        {
            get { return image.Value; }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (image.IsValueCreated) image.Value.Dispose();
            }
            image = null;
        }
    }

Logika zmiany obrazka - jak się pętla skończy to zaczynam od nowa i wczytuje nowe obrazy jakie zostały wklejone. To działa pięknie

        private void reklamySlider_CanGetNextPrevImage(object sender, CanGetNextPrevImageEventArgs e)
        {
            if (_currentImage.Next == null)
            {
                LoadImages();
                _currentImage = _images.First;
            }
            else
                _currentImage = _currentImage.Next;

            e.CanGetImage = true;
        }

        private void reklamySlider_GetImage(object sender, GetImageEventArgs e)
        {
            if(_images.Count > 0)
            {
                e.Image = _currentImage.Value.Image;
            }
        }

Chciałbym móc też usuwać obrazki ze ścieżki, ale Windows mnie nie puszcza, ponieważ plik jest w użyciu przez proces. Jest jakieś inne wyjście, aby zwolnić obrazek z pamięci?

0

Dla potomnych... Bardzo dziwne rozwiązanie, ale działa.

        public static Bitmap LoadBitmap(string path)
        {
            if(File.Exists(path))
            {
                using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    using (BinaryReader reader = new BinaryReader(stream))
                    {
                        var memoryStream = new MemoryStream(reader.ReadBytes((int)stream.Length));
                        return new Bitmap(memoryStream);
                    }
                }
            }

            return null;
        }

Wtedy event GetImage wyglądałby tak

        private void reklamySlider_GetImage(object sender, GetImageEventArgs e)
        {
           var image = Utils.LoadBitmap(_images[_currentImageIdx]);
           if(image != null)
               e.Image = image;
        }
0
AdamWox napisał(a):

Dla potomnych... Bardzo dziwne rozwiązanie, ale działa.

A bez udziwnień się nie da?
Tak zwycajnie:

        private void reklamySlider_GetImage(object sender, GetImageEventArgs e)
        {
            e.Image=new Bitmap(_images[_currentImageIdx]);
        }
0

No właśnie nie, bo sam Bitmap się nie zwalnia automatycznie.

0
AdamWox napisał(a):

No właśnie nie, bo sam Bitmap się nie zwalnia automatycznie.

Ze jak?
Kiedy i gdzie twoja wersja go zwalnia?
Kiedy i gdzie chcesz go zwolnić?

Czyli następujący program musi się wywalić dosyć szybko?

namespace ReadImageTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            new Thread
            (
                () =>
                {
                    Bitmap image = null;
                    for (int i = 0; ; ++i)
                    {
                        image = new Bitmap(@"C:\temp\event.png");
                        int ii = i;
                        Invoke(new Action(() => Text = ii.ToString()));
                    }
                }
            ).Start();
        }
    }
}

Czemu się nie wywala?

0

Przypominam, że w grę wchodzi kontrolka z DevExpressa, która przyjmuje Bitmap jako wartość e.Image w evencie GetImage(). I to właśnie DevExpress potwierdził, że nie zwalnia zasobów, nawet przy VirtualMode = true

0
AdamWox napisał(a):

Przypominam, że w grę wchodzi kontrolka z DevExpressa, która przyjmuje Bitmap jako wartość e.Image w evencie GetImage(). I to właśnie DevExpress potwierdził, że nie zwalnia zasobów, nawet przy VirtualMode = true

Ponawiam pytanie: - Kiedy i gdzie twoja wersja go zwalnia?

0

Usingi automatycznie robią Dispose() na obrazku i Windows nie marudzi, że plik jest w użyciu.

0
AdamWox napisał(a):

Usingi automatycznie robią Dispose() na obrazku i Windows nie marudzi, że plik jest w użyciu.

Konstruktor Bitmapy robi to samo.

0

Nie kombinowałbym gdyby było tak jak mówisz. Nie wiem czy Bitmap robi to samo w konstruktorze, wiem, że Windows nie pozwala mi usunąć pliku, który został już wczytany do slajdu.

0
AdamWox napisał(a):

Nie kombinowałbym gdyby było tak jak mówisz. Nie wiem czy Bitmap robi to samo w konstruktorze, wiem, że Windows nie pozwala mi usunąć pliku, który został już wczytany do slajdu.

Doprawdy?

namespace ReadImageTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            new Thread
            (
                () =>
                {
                    Bitmap image = null;
                    for (int i = 0, p = 0; ; ++i, p = 1 - p)
                    {
                        string FileName = @"C:\temp\event" + p + ".png";
                        File.Delete(FileName);
                        File.Copy(@"C:\temp\event.png", FileName);
                        using (Bitmap tmp = new Bitmap(FileName)) image = new Bitmap(tmp);
                        File.Delete(FileName);
                        int ii = i;
                        Invoke(new Action(() => Text = ii.ToString()));
                    }
                }
            ).Start();
        }
    }
}
0

Nie usuwam w kodzie, tylko ręcznie.

1
AdamWox napisał(a):

Nie usuwam w kodzie, tylko ręcznie.

Człowieku, skoro w kodzie możesz to ręcznie również!

0

Człowieku, skoro mówie, że się nie da, to nie z głowy, tylko faktycznie próbuję usunąć plik z obrazkiem, a Windows marudzi, że jest w użyciu przez inny proces. U mnie się nie da... Po co dalej drążyć?

0
AdamWox napisał(a):

Człowieku, skoro mówie, że się nie da, to nie z głowy, tylko faktycznie próbuję usunąć plik z obrazkiem, a Windows marudzi, że jest w użyciu przez inny proces. U mnie się nie da... Po co dalej drążyć?

Po to że perGolisz głupoty!

Masz 128 kopii pliku żadna z nich nie jest zwalniana no chyba że poczekasz 128 sekund.
Możesz sobie kasować dowolny z nich, jak zamienisz Thread.Sleep(1000); na Thread.Sleep(60000); to będziesz miał 60 sekund żeby sprawdzić czy plik da się skasować z systemu.

namespace ReadImageTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            new Thread
            (
                () =>
                {
                    Bitmap image = null;
                    for (int i = 0, p = 0; ; ++i, p = i%128)
                    {
                        string FileName = @"C:\temp\event" + p + ".png";
                        if(File.Exists(FileName)) File.Delete(FileName);
                        File.Copy(@"C:\temp\event.png", FileName);
                        using (Bitmap tmp = new Bitmap(FileName)) image = new Bitmap(tmp);
                        Thread.Sleep(1000);
                        int ii = i;
                        Invoke(new Action(() => Text = ii.ToString()));
                    }
                }
            ).Start();
        }
    }
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1