Выход из цикла while, который начался внутри асинхронного метода - PullRequest
1 голос
/ 01 июня 2019

Как разорвать цикл while внутри асинхронного метода.Пожалуйста, обратитесь ниже код

Я пробовал много способов, но ни один из них не работал для меня

async void TotalTimer(string time)
{
    while (true)
    {
        TimeSpan timesp = DateTime.Now - DateTime.Parse(time);
        TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
        await Task.Delay(1000);

        if (string.IsNullOrEmpty(time))
        {
            break;
        }
    }
}

Мне нужно остановиться и выйти из цикла


Обновленокод:

async Task TotalTimer(CancellationToken token)
{
    var intime = await App.Database.GetRecentIn();
    InTime = DateTime.Parse(intime.datetime).ToString("hh:mm tt");


    while (!token.IsCancellationRequested)
    {
        TimeSpan timesp = DateTime.Now - DateTime.Parse(intime.datetime);
        TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
        Console.WriteLine(TotalTime); // to see it's working
        await Task.Delay(1000);

        if (token.IsCancellationRequested)
        {
            break;
        }
    }
}

void StatCounting()
{
    var cts = new CancellationTokenSource();
   _= TotalTimer(cts.Token);
}

void StopCounting()
{
    var cts = new CancellationTokenSource();
    cts.Cancel();
   _= TotalTimer(cts.Token);

    _=Finalize();
}

Ответы [ 3 ]

5 голосов
/ 01 июня 2019

Используйте CancellationToken как это:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{
    class Program
    {
        private string TotalTime;

        static void Main(string[] args)
        {
            new Program().Run();
        }

        private void Run()
        {
            var cts = new CancellationTokenSource();
            TotalTimer("00:00:00", cts.Token);

            Console.ReadLine(); // waits for you to press 'Enter' to stop TotalTimer execution.
            cts.Cancel();
            Console.WriteLine("Press 'Enter' to exit the program.");
            Console.ReadLine();  // waits for you to press 'Enter' to exit the program. See, TotalTimer stopped.
        }

        // your original method modified
        async void TotalTimer(string time, CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                TimeSpan timesp = DateTime.Now - DateTime.Parse(time);
                TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
                Console.WriteLine(TotalTime); // to see it's working
                await Task.Delay(5000, token);
            }
        }
    }
}

Обновление

@ Хенк Холтерман, согласно истории изменений if (string.IsNullOrEmpty(time)) выглядит как попытка разорвать петлю извне. Но это бессмысленно по двум причинам:

  • строки неизменны
  • если time является нулевым или пустым DateTime.Parse(time) (это было в оригинальном посте) бросает перед проверкой

Добавление токена в Task.Delay является хорошим моментом. Это экономит ресурсы, но не имеет значения для наблюдаемого поведения.

Update2

@ Аргон, код не зависит от wpf, winforms, console или чего-либо еще. См. Минимальный wpf пример ниже. Я проверил, что это работает. Если что-то не работает с вашим конкретным кодом, возможно, вы скрываете некоторые детали от нас.

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private string TotalTime;
        private CancellationTokenSource cts;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            cts = new CancellationTokenSource();
            TotalTimer("00:00:00", cts.Token);
        }

        async void TotalTimer(string time, CancellationToken token)
        {
            try
            {
                while (!token.IsCancellationRequested)
                {
                    TimeSpan timesp = DateTime.Now - DateTime.Parse(time);
                    TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
                    label1.Content = TotalTime;
                    await Task.Delay(5000, token);
                }
            }
            catch(OperationCanceledException)
            {
                label1.Content = "Canceled";
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            cts.Cancel();
        }
    }
}
3 голосов
/ 01 июня 2019

Использование break в методе async прекрасно.

Это прекрасно работает:

async void Main()
{
    await TotalTimer();
    Console.WriteLine("Done.");
}

async Task TotalTimer()
{
    while (true)
    {
        await Task.Delay(1000);

        if (true)
        {
            break;
        }
    }
}

Он ждет секунду и затем пишет Done. в консоль.

Ваш код просто не меняется time, поэтому он никогда не достигает break.

Кроме этого, ваш async метод должен возвращать Task, а не void.

0 голосов
/ 01 июня 2019

Спасибо за ваши усилия, ребята.Я должен найти способ остановить цикл.Я определил логическое значение и проверил его в цикле while, чтобы разорвать цикл.Скорее всего, ответ @Enigmativity.

bool hasToStop = false;
while (true)
            {
                TimeSpan timesp = DateTime.Now - DateTime.Parse(intime.datetime);
                TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
                Console.WriteLine(TotalTime); // to see it's working
                await Task.Delay(1000);

                if (hasToStop)
                {
                    Console.WriteLine("Stoped");
                    break;
                }
            }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...