N
N
Nikolay Khablenko2021-06-23 02:08:38
WPF
Nikolay Khablenko, 2021-06-23 02:08:38

How to end a Task instantly?

Hello. Maybe someone will answer my question. In general, I'm developing an application, WPF, there are three IMAGE elements in the window. There is an animation flag. If the flag is off, then I output regular PNG files in Image.
There are also animations on the pictures, but not all. For example, 1 and 3 have animation, but 2 does not.
If the flag is on, then I output all the PNGs back, and then, using Task (since wpf does not support GIF, I display them in a separate thread through the redrawing of each frame), I start the animation. The whole point is that sometimes the flow remains, and when you select other pictures and animations, the frame of the previous animation freezes in the element.
The question is how to completely, and preferably, instantly, complete TASK and so that it does not hang in memory.

Here is the code of the Output itself

static CancellationTokenSource cancelTokenSource3 = new CancellationTokenSource();
        CancellationToken token3 = cancelTokenSource3.Token;
        public Task th_Image3;

        volatile bool volatileComplette1 = false;
        volatile bool volatileComplette2 = false;
        volatile bool volatileComplette3 = false;

                GifBitmapDecoder decoder3;
                BitmapSource bitmapSource3;
                int frameCount3;


                            th_Image3 = new Task(() =>
                            {
                                while (!volatileComplette3)
                                {
                                   
                                    if (token3.IsCancellationRequested)
                                    {
                                        return;
                                    }
                                    for (int c = 0; ((c < frameCount3)&& (!volatileComplette3)); c++)
                                    {
                                       
                                        this.Dispatcher.Invoke(new Action(delegate ()
                                        {
                                            bitmapSource3 = decoder3.Frames[c];
                                            Image_Right.Source = bitmapSource3;
                                            
                                            if (token3.IsCancellationRequested)
                                            {
                                                return;
                                            }
                                        }));
                                        System.Threading.Thread.Sleep(30);
                                        if (token3.IsCancellationRequested)
                                        {
                                            return;
                                        }

                                    }
                                
                              
                                    if (token3.IsCancellationRequested)
                                    {
                                        return;
                                    }
                                }
                         
                            }, token3);
                            th_Image3.Start();

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Alexey Bereznikov, 2021-06-23
@NikolayKhablenko

Sorry for not answering your question - why don't you use https://github.com/XamlAnimatedGif/XamlAnimatedGif ?
In fact - if my memory serves me, there is no easy way to beat the Task, for this you need to use CancellationTokenSource, which is what you do in the above example. If cancellation via CancellationTokenSource does not work for some reason - set breakpoints or stick logs through each line, find a problematic place, and decide based on this information.
Based on your problem, to start after canceling, you can simply wait for the task to complete:

// Метод в котором останавливаете анимацию
cancellationTokenSource3.Cancel();
await th_Image3;

or
// Метод в котором останавливаете анимацию
cancellationTokenSource3.Cancel();
th_Image3.GetAwaiter().GetResult();

So you should at least get rid of tasks overlapping each other.
Further, tasks can be launched a little easier, like this:
th_Image3 = Task.Run(() => 
{ 
    // ......
});

In addition, if you really need the code inside Task.Run to always be executed only in a single instance, this means that you need a critical section. In this case, you can do it with semaphores:
// ......................
Semaphore _semaphore = new Semaphore(1, 1);
// ......................
th_Image3 = Task.Run(() =>
{
    _semaphore.WaitOne();

    try
    {
        // Показ GIF
    }
    finally
    {
        _semaphore.Release();
    }
});

Or you can use the ContinueWith method to create some kind of task queue:
// .................................................
Task th_Image3 = Task.FromResult(0);
// .................................................
th_Image3 = th_Image3.ContinueWith(() => 
{
    // Отображение GIF
});

In general, a lot of things can be done, the easiest way is not to reinvent the wheel and take a ready-made solution.

N
Nikolay Khablenko, 2021-06-23
@NikolayKhablenko

And yet, about the animation, it should start and run until I press the button to the next animation, so the while is looped

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question