Dilshod
Dilshod

Reputation: 3331

WPF memory issue

I am trying to load pictures with the code below:

void LoadPictures(int s)
{
    grdScene.Children.Clear();
    TabControl tab = new TabControl();
    for (int i = s; i <= s+3; i++)
    {
        System.Drawing.Bitmap bmp = new System.Drawing.Bitmap("C:\\img\\" + i + ".png");
        TabItem tabItem = new TabItem();
        tabItem.Header = "Scene " + i;
        var bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(),
                                                                    IntPtr.Zero,
                                                                    Int32Rect.Empty,
                                                                    BitmapSizeOptions.FromEmptyOptions());
        Image image = new Image();
        image.Source = bitmapSource;
        tabItem.Content = image;
        tab.Items.Add(tabItem);
    }
    grdScene.Children.Add(tab);//grdScene is Grid
}

it works fine but every time I run this method the memory is going up. Then I tried to set all the items to null, but no success. Here is the code:

foreach (var child in grdScene.Children)
{
    TabControl tab1 = (TabControl)child;
    foreach (TabItem item in tab1.Items)
    {
        Image img = (Image)item.Content;
        img = null;
    }
    tab1 = null;
}

I tried GC.Collect() but nothing changes. What should I do to solve this problem?

Upvotes: 1

Views: 360

Answers (2)

Clint
Clint

Reputation: 6220

Why are you doing this via code-behind?

From the look of your code the tab items are populated entirely by the image.

You could just bind a tabcontrol to the image path collection and use a style to describe the look you're after, it'd be a lot simpler and the WPF core would then be taking care of the image loading and memory management itself.


If that's not usable for you then your issue is coming from how you're loading the image, you're doing it via an unsafe interop method that doesn't release the memory for you, you have to dispose of the bitmap youreself .Dispose()

You'd be better doing: loading the source of a BitmapImage in WPF?

Using BitmapImage is likely the better way to go if you want to remain doing it in the code-behind rather than the Interop methods.

SO:

    void LoadPictures(int s)
    {
        grdScene.Children.Clear();
        TabControl tab = new TabControl();
        for (int i = s; i <= s + 3; i++)
        {
            BitmapImage bmp = new BitmapImage(new Uri("C:\\img\\" + i + ".png"));
            TabItem tabItem = new TabItem();
            tabItem.Header = "Scene " + i;
            tabItem.Content = new Image(){Source = bmp};
            tab.Items.Add(tabItem);
        }
        grdScene.Children.Add(tab);
    }

Should do the trick.

Upvotes: 2

I4V
I4V

Reputation: 35363

Try to call Dispose on all IDisposables, such as System.Drawing.Bitmap or better use using..

using(var bmp = new System.Drawing.Bitmap("C:\\img\\" + i + ".png"))
{
     .....
}

Upvotes: 2

Related Questions