Hey there,

Over the past few weeks as an excerise I've been trying to create a C# image viewer. At the moment I have one window, with a list of images displayed in a ListBox.

When I the F5 button, a second window pops up at fullscreen, and I want it to cycle through all the images shown in the previous screen. At the moment, the picture folder is simply My Pictures.

In order to simulate a cross-fade effect, I have two image objects on my canvas, PreviewImages and Background. The idea is that Image 1 = Background.Source whilst PreviewImages.Source = Image 2. Because I have a DoubleAnimation fade in effect, it will appear like image 1 and 2 are crossfading. The script then leads onto the next image in the series after a Task.Delay.

HOWEVER, my issue is that for some reason I cannot explain, after a while operating the code (say 10 minutes) instead of showing a ncie cross fade, the code plays up and starts skipping images and the cross fade completely breaks, instead it appears like Background.Source becomes some random image, so the result is an instant snap to an unrelated image, followed by an instantaneous the fade in of the "correct" image.

The code I am using for this is:

        public async void transition()
        {
            while (App.timer = true)
            {
                for (App.index = 0; App.index < AllImages.Count; App.index++)
                {                     

                        DoubleAnimation fadeoutAnimation = new DoubleAnimation();
                        fadeoutAnimation.Duration = TimeSpan.FromSeconds(1.0);
                        fadeoutAnimation.From = 0;
                        fadeoutAnimation.To = 1;
                        PreviewImages.BeginAnimation(Image.OpacityProperty, fadeoutAnimation);
                        await Task.Delay(5000);
                        PreviewImages.Source = new BitmapImage(new Uri(Convert.ToString(AllImages[App.index]._image)));

                    if (App.index < (AllImages.Count - 1) && App.index > 0)
                    {
                        App.index2 = App.index - 1;
                    }

                    else if (App.index < 1)
                    {
                        App.index2 = (AllImages.Count - 1);
                    }
                        Background.Source = new BitmapImage(new Uri(Convert.ToString(AllImages[App.index2]._image)));
                }
            }
        }

The list of images is populated by:

  public List<MyImage> AllImages
        {

            get
            {
                List<MyImage> result = new List<MyImage>();

                foreach (string filename in
                    System.IO.Directory.GetFiles(
                        Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)))
                {
                    try
                    {
                        result.Add(
                            new MyImage(
                            new BitmapImage(
                            new Uri(filename))));

                    }

                    catch { }
                }
                return result;

            }

        }

Is someone able to tell me if there are any mistakes here? I find it incredibly odd that it starts by working fine, but only after a while starts going wrong. That makes me think its an issue with the App.index++

Just as a quicj wild stab...

{
      App.index2 = App.index - 1;
}

;To

{
      App.index2 = (App.index - 1);
}

Okay, I've added the brackets in. The problem is that I can never seem to replicate the issue.

Like I said, when I start it up everything works fine. I've experimented with decreasing the Task.Delay to simulate a lot of transitions in a short amount of time, but even when I do that everything still works.

Having said that, the error is still there. If I connect the laptop the programme is running on to a TV via HDMI (which is what I've designed this to do), then the error always happens.

I would attach the source code, but Daniweb is saying I can't attach RARs, so not sure how to share it with you.

It may be relevant to add that on a different window, I use a different list of images that you can navigate through by clicking manually. When the user launches this screen from the slideshow, it sets App.timer = false; to stop the image transitions in the background at the next foreach statement. When the user exits the manual slideshow screen, App.timer = true;

      void MainWindow_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            int count = Slides.Count;

            if(e.Key == System.Windows.Input.Key.PageDown)
            {

                if (program.count < (Slides.Count - 1))
                {
                program.count = program.count + 1;
                PreviewImages.Source = new BitmapImage(new Uri(Convert.ToString(Slides[program.count]._image)));
                }

                else
                {
                    program.count = 0;
                    App.timer = true;
                    this.Close();
                }
        }

And when the user exits:

           else if (e.Key == System.Windows.Input.Key.OemPeriod)
            {
                App.timer = true;
                this.Close();
            }

](null)

It is a possibility that your laptop might not have the resources available to run this progran through hdmi.

It is also possible that cpu is getting hammered in a loop, and they both could be connected.

Are you using multiple threads? and is your laptop multi core?

Just a few of things to consider.

Try adding a Thread.Sleep(5); or something to any tight loops you might be entering

You may have a point. I am coding on a i5 Quad Core PC, but running the programme off a laptop (there are two I have tried it on). Both are dual core.

However, I have used Windows Task Manager to track the performance, and the application (when looping) only uses about 30% of the processor power. The largest draw was actually Hard Disk access, but I think that was because the images I provided where too large, so I scaled them down and it seems fine.

So I don't think it is the CPU. Also, when the error occurs, it definitely looks like something is wrong in the code. By that I mean that the program actually behaves exactly as it should, it's just for some reason Background.Source and PreviewImage.Source take on images that they shouldn't do.

Since I'm a beginner to programming in general, I'm not familiar with utilising multiple CPU threads. I am aware that using Task.Delay with an async method allows the programming to continue running by generating an additional thread to run Task.Delay. Can you elabroate or provide resources on what you mean by using multiple threads?

Same goes for Thread.Sleep. Are you suggesting that I use this to create a pause between each foreach statement (which loops under the while() statement) to see if that makes a difference?

Thanks for your input!

I'm not 100% on this but from what I've read in the past it seemed that using multiple threads should only be done on multi core processors (a thread per core max I read).

C# is managed code and I'm uncertain whether it manages loops which might max out a cpu. In C++ it is always wise to add a Sleep to a tight loop in the process to allow the processor time to do any other operations on other processors But if you say it only takes 30% (which I fear is still a little high for a single process) it may not be the issue.

Basically, monitor task manager while you app is running for spikes in CPU and Memory and although C# in managed, coming from C++ I still think it wise, and certainly cannot do any harm, to manually dispose of any objects you create when they are no longer needed.

Sorry I cannot offer any advice on your code, it looks ok to me without any other context, but in lieu of someone else who can, is why I offer my suggestions.

Edited 1 Year Ago by Suzie999

30% did seem to jump out at me as quite a high load for some relatively minor code.

I'll run the programme through on its own and connected via HDMI output to see what the load is like and get back to you.

Okay, so I've taken another look at this.

I was wrong about the CPU usage, I was only able to clock it up to about 3% of total use. The biggest drain was the RAM at approx. 300mb.

However, I was able to replicate the error - so there is definitely something wrong! My process was:

Launch the second screen (the linear slide show, where PageUp and PageDown navigate through slides). I mashes the keyboard with those two keys for a few seconds, the programe was fully able to keep up with those transitions. I then went to the last image, which triggers the this.close(); and sets app.timer = true; again.

It was then that the error happend! The counts for the image sources were completely off. Could it be because I cancel and then resume the while() statement?

Could it be because you are closing the window while the transition animation is still in progress? Maybe try stopping the animations before closing the window?

Which window are you talking about?

Window 2 with the linear slideshow has no fade transitions using DoubleAnimation, it simply snaps to the next one. Window 1 should stop the transitions when Window 2 launches and the While() statement returns false.

I've actually just made a small modification. I realised using a for statement was silly because when the while() returns false it would still cycle through each iteration before finishing. So now I just make use of while:

 if (App.index < AllImages.Count)
                {
                    DoubleAnimation fadeoutAnimation = new DoubleAnimation();
                    fadeoutAnimation.Duration = TimeSpan.FromSeconds(1.0);
                    fadeoutAnimation.From = 0;
                    fadeoutAnimation.To = 1;
                    PreviewImages.BeginAnimation(Image.OpacityProperty, fadeoutAnimation);


                    await Task.Delay(2000);
                    PreviewImages.Source = new BitmapImage(new Uri(Convert.ToString(AllImages[App.index]._image)));

                    if (App.index < (AllImages.Count) && App.index > 0)
                    {
                        App.index2 = (App.index - 1);
                    }

                    else if (App.index < 1)
                    {
                        App.index2 = (AllImages.Count);
                    }

                    Background.Source = new BitmapImage(new Uri(Convert.ToString(AllImages[App.index2]._image)));
                }

                else { App.index = 0; }

                App.index++;

            }

The interesting thing is, I think this shows what's wrong with the code - but I cannot figure out exactly what. Everything works fine except when the first image in the list, so my two if statements

  if (App.index < (AllImages.Count) && App.index > 0)
                        {
                            App.index2 = (App.index - 1);
                        }

                        else if (App.index < 1)
                        {
                            App.index2 = (AllImages.Count - 1);
                        }

are somehow incorrect.

At the moment, when the first image gets shown in the loop, it only shows it for a very small time, and then jumps to the next item in the fade very quickly.

At this point I imagine Background.Source = first image and App.index = first image + 1... What it SHOULD be is Background.Source = (AllImages.Count - 1) and App.Index = 0.... Which is exactly what happens in the if statement.

Quick question, where are we at with this? I have developed software to fade images in and out (transitioning them), and after many attempts have a good working solution

(MIne was for a screen saver to fade in and out images, works smoothly, and does well with memory management)

Edited 1 Year Ago by JOSheaIV

How does your transition code compare to mine? As you can see I use two image elements to simulate the cross fade - do you do something different?

I might try host the source code somewhere for you all to look at, since I can't attach it here.

Scanning you code quickly, there are some similarities with yours and mine, but I do see differences as well (for instance that Task.Delay). I actually built mine off a WPF User Control, of two Images, that can fade in and out (staggering, you pass in a filename of an image and it loads it in, and fades out the last, it's smart enough to know which to fade in and out).

I assume this could theoretically work here, every time you change images you pass in the filepath. I am trying to remember I think I set my transition time at 2 sec, but to be honest, with DoubleAnimations (or was it the storyboard ... can't recall at the moment, still waking up), you actually set this to what you want.

Nice thing is because it's WPF, it's on a sepereate thread (I believe I read once it uses DirectX).

So just looked at it again, I do see you using some of the pieces I did to do animation type effects, but where you only had one, I had two (one to fade in, one to fade out, at the same time) ... unless I am looking at something wrong here. Also have to ask, have you be getting any memory issues with using those BitmapImages? I remember I had to fight with this issue for awhile.

BTW I just re-read your original post, you might be running into issues with your memory (my guess is that BitmapImage has to do with it)

Edited 1 Year Ago by JOSheaIV

You're right that I am just using one double animation, a true cross fade would dip in the middle, but I like having the previous background visible on the fade up.

Can you elaborate on the WPF User Control? I am using a C# WPF form (but I'm really new to all this, I don't really understand what that means!) Do you just mean that you used a timer? I started using that, but then moved to the Task.Delay, which I feel is a much better solution under the While() than having something continuously counting.

Specifically, I think the problem is with my loop. Even if there is high memory usage with the BitmapImage, I can't see how that would force the loop to lose count of its variables, which seems to be what's happening. I think it's more plausible that I've got the coding wrong.

Cool, I'll try and check it out tonight when I get home from work.

Also, a WPF User Control can be used for instance in a WPF Form or Windows Form, it's like taking a collection of components (say for instance a TextBox, Image, and a Label, combining them into one component that can then be used and you can write logic around). I have a whole collection of these like one is a PictureBox and label that is designed to be used in a TableLayoutView (so it offers hover color change and select color change, ext).

I believe it's the double animation, or maybe it's a storyboard that does it. But WPFs have a way to control with a timer, and they run on their own thread, no need for a task delay.

Now if you are losing variables, this could be an issue with the code, I'll have to look at it again. But also, those BitmapImages can be unforgiving when it comes to memory usages. One of the annoying things I have come to learn, is the whole "Dispose" seems to be rather sparce in WPFs (my program used them and originally had a leak so bad, it would grow to over a GB of RAM used in like a minute or less).

Edited 1 Year Ago by JOSheaIV

Thanks, I'd appreciate it if you could take a look at the code :) Just a note that it search for pics from your my pictures folder, so there has to be something there

Sorry I didn't look at it last night, I'll see if I can tonight (I might have plan) but if not tomorrow. (Also I have an idea what you are going for with this design, I have thought about using some of my screensaver code once to do something like this)

This article has been dead for over six months. Start a new discussion instead.