Jak zatrzymać wykonywanie zadania await.task.Run()?

0

Hej ! :)
Mam do wykonania 3 rzeczy:

  1. Wczytać stream,
  2. Określić amplitudy dźwięków i zapisać je w liście,
  3. Narysować widmo dźwięku w Canvasie w oparciu o tą listę

Z racji tego, że są to czasochłonne procesy użyłem do tego csharp await.Task.Run()

Przy zmianie rozmiaru Canvasa owy obraz powienien się odrysować na nowo, co wiąże się z wywołaniem kolejnego zadania. Stanąłem przed wyzwaniem sprawdzenia, czy obraz się w danym momencie nie rysuje i zatrzymać go, a następnie zacząć tworzenie obrazu z nowymi rozmiarami. Postanowiłem użyć do tegocsharp CancellationToken.
Wygląda to mniejwięcej tak:

private async Task DetectWaveformAsync(int Length)
        {
            try
            {
                if (DetectWaveFormCancellationToken != null)
                    DetectWaveFormCancellationToken.Cancel();

                DetectWaveFormCancellationToken = new CancellationTokenSource();
                await Task.Run(() => {
                    MaxLvl = 0;
                    UpperList.Clear();
                    LowerList.Clear();

                    // Fill Double List
                    for (int i = 0; i < Length; i += 1)
                    {
                        // Get left and right levels.
                        float[] levels = new float[2];
                        Bass.BASS_ChannelGetLevel(Stream, levels);
                        float leftLevel = levels[0];
                        float rightLevel = levels[1];
                        // Set MaxLvl
                        if (leftLevel > MaxLvl)
                            MaxLvl = leftLevel;
                        if (rightLevel > MaxLvl)
                            MaxLvl = rightLevel;
                        //Fill List
                        UpperList.Add(leftLevel);
                        LowerList.Add(rightLevel);
                        ProgressPercentage = HowManyPercent(i, Length);

                        DetectWaveFormCancellationToken.Dispose();
                        DetectWaveFormCancellationToken = null;
                    }
                    DetectWaveSucces();
                },
                DetectWaveFormCancellationToken.Token
                );
            }
            catch (OperationCanceledException)
            {
                DetectWaveAborted();
                DetectWaveFormCancellationToken.Dispose();
                DetectWaveFormCancellationToken = null;
            }
            catch (Exception)
            {

            }
        }
private CancellationTokenSource DetectWaveFormCancellationToken = null;

Zastanawiam się, czy samo wywołanie:

if (DetectWaveFormCancellationToken != null)
{
     DetectWaveFormCancellationToken.Cancel();
     DetectWaveFormCancellationToken.Dispose()
}

wystarczy, aby wymusić wywołanie ```csharp
catch (OperationCanceledException)

0

Na msdnie jest to ładnie opisane jak tego należy użyć prawidłowo(czytaj masz sprawdzać IsCancellationRequested, a nie liczyć na rzucenie wyjątku):
https://msdn.microsoft.com/pl-pl/library/system.threading.cancellationtokensource(v=vs.110).aspx

The general pattern for implementing the cooperative cancellation model is:

    Instantiate a CancellationTokenSource object, which manages and sends cancellation notification to the individual cancellation tokens.

    Pass the token returned by the CancellationTokenSource.Token property to each task or thread that listens for cancellation.

    Call the CancellationToken.IsCancellationRequested method from operations that receive the cancellation token. Provide a mechanism for each task or thread to respond to a cancellation request. Whether you choose to cancel an operation, and exactly how you do it, depends on your application logic.

    Call the CancellationTokenSource.Cancel method to provide notification of cancellation. This sets the CancellationToken.IsCancellationRequested property on every copy of the cancellation token to true.

    Call the Dispose method when you are finished with the CancellationTokenSource object. 
0

Ok, poprawione. Zmieniam trochę strukturę kontrolki. Czy tak będzie dobrze?
screenshot-20170704041559.png
ViewModel odpowiada za obsługę wątków wewnątrz 3 klas "stream", "wave" i "timeline".
Może lepiej zrobić jeszcze oddzielna klasę do zarządzania wątkami, a w ViewModelu trzymać tylko wynik tych operacji (czyli wizualizację) oraz przechwytywać eventy np. procent ukończenia renderowania? A. I korzystniej chyba w tym przypadku przerobić zadania na wątki Thread, co? Bo przecież w jednym momencie będzie się wykonywał tylko 1 wątek.

0

Generalnie w viewmodelu powinno być jak najmniej. Powinieneś potworzyć klasy odpowiedzialne za te rzeczy po "lewej stronie" i wewnątrz viewmodelu jedynie wywoływać ich metody. Oczywiście w miarę możliwości. Powstanie wtedy taki model, który w zasadzie będzie autonomiczny.

Co więcej: rzeczy związane stricte z widokiem, a niezależne od logiki "biznesowej" możesz spokojnie napisać w code-behind. Nie złamiesz wtedy mvvm,

Myślisz dobrze ale wystrzegaj się wielkich i przepastnych viewmodeli.

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