locked
Running a Task which allows user-initiated cancellation RRS feed

  • Question

  • I'm quite a beginner on async programming and I'd like some help here:

    My C#/WPF .NET 4.6.1 app needs to write a text file, which a service, with a running detection loop will read, process, erase and write another text file (on a separate folder), which my app needs to monitor. Depending on the type of interaction between the processes, the time the service takes to generate the reply file can go from 5 seconds to 30 seconds, during which the user can press "ESC" to cancel the task. The task [i]must[/i] return a <string, string> dictionary, filled either with information taken from the reply file, or a single ("XXX-XXX", "Error") entry.

    I've been researching on Async Tasks, and I'm trying to implement this. As of now this is what I have:

    MainWindow.xaml.cs. The interface has one button and one textbox.

            private void Button_Click(object sender, RoutedEventArgs e)
            {
                StartTheTask();
            }
            private async void StartTeTask()
            {
                CRT Sale1= new CRT()
                {
                    _001 = 34430576,
                    _002 = 223546,
                    _003 = 100,
                    _717 = DateTime.Now
                };
                Dictionary<string, string> REPL_SALE= await Sale1.SendSale();
    
                MessageBox.Show(REPL_SALE["000-000"]);
            }

    SaleSystem.cs. This file will be referred throughout the application.

        class CRT
        {
            Dictionary<string, string> resultado = new Dictionary<string, string>();
            public int _001 { get; set; }
    
            public async Task<Dictionary<string, string>> EnviaVenda()
            {
                string _path1 = @"C:\PAYMENT\Req\intpos.tmp";
                string path1 = @"C:\PAYMENT\Req\intpos.001";
                string path2 = @"C:\PAYMENT\Repl\intpos.001";
                string path3 = @"C:\PAYMENT\Repl\intpos.sts";
                try
                {
                    using (StreamWriter sw = File.CreateText(_path1))
                    {
                        sw.WriteLine("000-000 = CRT");
                        sw.WriteLine(String.Format("001-000 = {0}", _001.ToString()));
                        sw.WriteLine(String.Format("736-000 = 1.0.0"));
    					//		.
    					//		.
    					//		.
    					// Code that sucessfully generate the request file.
    					//		.
    					//		.
    					//		.
                        sw.WriteLine(String.Format("738-000 = CERTIFICATESTRING"));
                        sw.WriteLine(String.Format("999-999 = 0"));
                    }
                    File.Move(_path1, path1);
                }
                catch (Exception)
                {
                    reply.Add("XXX-XXX", "Error.");
                    return Task.Run(()=> reply);
                }
                for (int i = 0; i < 240000; i++) // The service's developer asks a 1 minute window to allow the processing to happen, as it
                {								  // requires user interaction, while still needing a timeout.
                    if (File.Exists(path2))
                    {
                        using (StreamReader sr = new StreamReader(path2))
                        {
                            string line;
                            while ((line = await sr.ReadLineAsync()) != null)
                            {
                                reply.Add(line.Substring(0, 7), line.Substring(10).Replace("\"", String.Empty)); // Each line is a string in the format '###-### = SOMEWORDS', which 
                            }																					   // must be individually readable.
                            return Task.Run(() => reply);
                        }
                    }
                    System.Threading.Thread.Sleep(250); // The service's developer also asks that not more than 4 file checks be made each second so not to divert processing power from the service.
                }
                reply.Add("XXX-XXX", "Error.");
                return Task.Run(() => reply);
            }
        }

    However, as I run this code, the main window still freezes while the task is running. I understood that when I call an async method the method will start whatever task I add the await keyword before. Which is not what's happening. What am I doing wrong here?



    • Moved by Fei Hu Thursday, January 18, 2018 10:04 AM WPF related
    • Edited by Artur_Sousa Thursday, January 18, 2018 12:03 PM
    Wednesday, January 17, 2018 7:29 PM

Answers

  • Hi Artur_Sousa,

    Sorry for my late reply.

     >> I first need my UI not to freeze while waiting for the file to show up. When I call the Button_Click method, the UI freezes until either the for loop ends, or the app finds the file.

    For very expensive operations you should use Multithreading, and you 'd best use await/async to make your code running in asynchronous way.

    For Button Click method , you should run in asynchronous way as following code.

    private async void DoTask_Click(object sender, RoutedEventArgs e) {

    //...... var result= await Task.Run=> {

    //Long Task

    //..... });

    // ..... }

    Note that if you want update UI in another thread not the UI thread. You need get the Dispatcher of UI thread ,and then call Invoke method which specified an Action to update the UI in UI thread. Something like following code.

     if (DownloadProgress.Dispatcher.CheckAccess())
                {
                    DownloadProgress.Dispatcher.Invoke(() => { DownloadProgress.Visibility = Visibility.Hidden; });
                }

    Sincerely,

    Bob


    • Edited by Bob Ding Tuesday, January 23, 2018 9:36 AM
    • Marked as answer by Artur_Sousa Tuesday, May 8, 2018 12:48 PM
    Tuesday, January 23, 2018 9:35 AM

All replies

  • Hello,

    Sounds like you need a cancellation token.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Wednesday, January 17, 2018 8:28 PM
  • Hi Arthur,

    According to your question is more related to WPF, I will move the thread to WPF forum for suitable support.

    The Visual C# discuss and ask the C# programming language, IDE, libraries, samples and tools. If you have some grammar or code errors, please feel free to contact us. We will try our best to give you a solution.

    Best Regards,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, January 18, 2018 10:03 AM
  • Before even working with a cancellation token, I first need my UI not to freeze while waiting for the file to show up. When I call the Button_Click method, the UI freezes until either the for loop ends, or the app finds the file.

    After further reading I've noticed the issue is how I'm checking if the file exists. I needed a way to monitor when/if the specified file is created, and "if (File.Exists(path))" does not run asynchronously. Is there a way to asynchronously "monitor" when a file is created?

    • Edited by Artur_Sousa Thursday, January 18, 2018 12:11 PM
    Thursday, January 18, 2018 12:03 PM
  • Hi Artur_Sousa,

    Sorry for my late reply.

     >> I first need my UI not to freeze while waiting for the file to show up. When I call the Button_Click method, the UI freezes until either the for loop ends, or the app finds the file.

    For very expensive operations you should use Multithreading, and you 'd best use await/async to make your code running in asynchronous way.

    For Button Click method , you should run in asynchronous way as following code.

    private async void DoTask_Click(object sender, RoutedEventArgs e) {

    //...... var result= await Task.Run=> {

    //Long Task

    //..... });

    // ..... }

    Note that if you want update UI in another thread not the UI thread. You need get the Dispatcher of UI thread ,and then call Invoke method which specified an Action to update the UI in UI thread. Something like following code.

     if (DownloadProgress.Dispatcher.CheckAccess())
                {
                    DownloadProgress.Dispatcher.Invoke(() => { DownloadProgress.Visibility = Visibility.Hidden; });
                }

    Sincerely,

    Bob


    • Edited by Bob Ding Tuesday, January 23, 2018 9:36 AM
    • Marked as answer by Artur_Sousa Tuesday, May 8, 2018 12:48 PM
    Tuesday, January 23, 2018 9:35 AM