Solved

c# Tasks - How to wait for events

Posted on 2014-10-29
4
1,584 Views
Last Modified: 2014-12-15
Hi,

I have some code which initiates a download. This results in one of the following async events being triggered. I need the application to wait for one of these events before continuing.

Is this a job for tasks? Can I create a task with my download code which returns 'task complete' when one of the 3 events below fire?

(stdFile_.saver as _IStreamCollectorEvents_Event).stopped += (collector) =>
{
	Console.WriteLine("Download stopped");
};
(stdFile_.saver as _IStreamCollectorEvents_Event).failed += (sender, error) =>
{
	Console.WriteLine("Download failed");
};
(video as _IStream_Events_Event).stopped += (s) =>
{
	Console.WriteLine("Download Complete!");
};

Open in new window

0
Comment
Question by:mhdi
  • 2
4 Comments
 
LVL 24

Accepted Solution

by:
chaau earned 250 total points
ID: 40412359
You can use a WaitHandle class. Register it before the download starts. Then just use the WaitOne() method in the main program. I recommend you use the version of the method where you can specify the timeout to make sure your program does not forever. The pseudo code will be similar to this:

Create a global variable:
static AutoResetEvent autoEvent = new AutoResetEvent(false);

Open in new window

Then in your main program start your download and wait:
       Console.WriteLine("Main starting.");

        // your code for asynchronous download here. 

        // Wait for work method to signal. 
        if(autoEvent.WaitOne(1000))
        {
            Console.WriteLine("download event signaled.");
        }
        else
        {
            Console.WriteLine("Timed out waiting for download");
        }
        Console.WriteLine("Main ending.");

Open in new window

And your evens all do the same:
(stdFile_.saver as _IStreamCollectorEvents_Event).stopped += (collector) =>
{
	Console.WriteLine("Download stopped");
	autoEvent.Set();
};
(stdFile_.saver as _IStreamCollectorEvents_Event).failed += (sender, error) =>
{
	Console.WriteLine("Download failed");
	autoEvent.Set();
};
(video as _IStream_Events_Event).stopped += (s) =>
{
	Console.WriteLine("Download Complete!");
	autoEvent.Set();
};
                                  

Open in new window

You may also wish to introduce a global string variable for status to indicate the result of your download
0
 
LVL 14

Assisted Solution

by:Tchuki
Tchuki earned 250 total points
ID: 40412735
Ideally you do not want to block whilst the operation is in progress, so making use of the TPL is a viable option (there is also the older and still valid BackgroundWorker class).

The following example should get you most of the way to what you are looking for:

namespace EE.Q_28547351.ConsoleApp
{
    using System;
    using System.Threading;
    using System.Threading.Tasks;

    internal class Program
    {
        private static CancellationTokenSource cts;

        private static void Main(string[] args)
        {
            // Create a new CancellationTokenSource so that the task can be cancelled if required
            cts = new CancellationTokenSource();
            // Start the operation
            var task =
                Task.Run(() => DownloadOperation(new Progress<ProgressReport>(ReportProgress)), cts.Token)
                    .ContinueWith(TaskComplete);

            Console.WriteLine("Task running ...");
            Console.WriteLine("Press any key to cancel the process");
            Console.ReadKey();

            // Cancel the task
            cts.Cancel();

            Console.ReadKey();
        }

        // Download operation simulates where you would perform your long running process
        // This is where you will perform your download
        // I have added a delay to simulate a long running download
        private static async Task<bool> DownloadOperation(IProgress<ProgressReport> progress)
        {
            const int totalAmount = 10;
            for (var i = 1; i <= totalAmount; i++)
            {
                if (cts.IsCancellationRequested)
                {
                    return false;
                }
                await Task.Delay(1000);
                progress.Report(new ProgressReport
                {
                    CurrentProgressAmount = i,
                    TotalProgressAmount = totalAmount,
                    Message = i == totalAmount ? "All done" : "More to do"
                });
            }

            return true;
        }

        private static void ReportProgress(ProgressReport report)
        {
            Console.WriteLine(report);
        }

        private static void TaskComplete(Task<bool> task)
        {
            // Do something when the task completes
            Console.WriteLine(task.Result);
        }
    }

    // Encapsulates progress information and is used by the IProgress<T> interface
    internal class ProgressReport
    {
        public int CurrentProgressAmount { get; set; }
        public int TotalProgressAmount { get; set; }
        public string Message { get; set; }

        public override string ToString()
        {
            return string.Format("Processing {0} of {1}. {2}", this.CurrentProgressAmount, this.TotalProgressAmount,
                this.Message);
        }
    }
}

Open in new window

0
 

Author Comment

by:mhdi
ID: 40423311
Apologies for the late reply guys.

@chaau - I need the ability to signal the main thread whether the download completed successfully or not. Can I do this with the "AutoResetEvent"?  Or do I keep a separate variable which holds the download status. eg "bool downloadComplete = false" which gets changed to "true" when the download complete event is fired.

@Tchuki - I like your proposed solution, but how do I tie in the events mentioned in my top post?
0
 
LVL 24

Expert Comment

by:chaau
ID: 40423359
You just need the AutoResetEvent, and set it

autoEvent.Set();
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now