Thursday, February 12, 2015

Task With A Return Value



namespace TasksThatReturnAValue
{

    public partial class Form1 : Form
    {
        //Use the Task<TResult> class to represent an asynchronous method that returns a value
        //Use the Func<..TResult> delegate with the Task<TResult> class
        Random rand = new Random();
        public Form1()
        {
            InitializeComponent();
        }
        //Not a good way, but to know the difference
        private void btnStartTask1_Click(object sender, EventArgs e)
        {
            //Create a Func<> delegate

            Func<long> function = ComputeTotalOfRandomNumbers;
            //create a Task
            Task<long> task1 = new Task<long>(function);
           
            //start task1
            task1.Start();
            //get the returned value for the Task Result Property
            long total = task1.Result;
            //But the disadventage of doing this way is 
            //result property will block/waits until the result is returned 
            //from the asynchronous method / until task1 completes
            //Since the task1.Result runs on the main thread, it will lock the UI 
           
            //display
            richTextBox1.AppendText("Total of a list of randoms is: \n" + total + "\n");

        }

        private long ComputeTotalOfRandomNumbers()
        {
            int counter = 0;
            long sum = 0;

            do
            {
                int num = rand.Next();
                if (num % 2 != 0)
                {
                    sum += num;
                    counter++;
                }
            } while (counter < 1000000);
            return sum;
        }

        private void btnStartTask2WithoutLockingUI_Click(object sender, EventArgs e)
        {
            //Need to take the statement Task1.Result from the main thread and put it in another task
            //but the second task can only start when the first one complete

            //task1 is ready to be passed to task2

            //Start task1 same way as the previous 
            //Create a Func<> delegate
            Func<long> function = ComputeTotalOfRandomNumbers;
            //create a Task
            Task<long> task1 = new Task<long>(function);

            //start task1
            task1.Start();

            //Create a second task that starts or continues when the first one completes
            //The Task<TResult> class defines the method ContinueWith that creates and starts
            //a second task when the first one completes

            //Use: public Task ContinueWith(Action<Task> continuationAction)
            //so the Action<Task> represents a method (as a callback method that takes a Task as a 
            //parameter. You could define such method or use a Lambda expression
            Action<Task<long>> action = delegate(Task<long> t)//Task represents the completed task, task1
            {
                //get the return value]
                long total = t.Result;
                //display it// apply the cross threading calls.
                SetText(total.ToString(), richTextBox1);
            };

            //or
            //Action<Task<long>> action1 = t =>
            //{
            //    long total1 = t.Result;
            //    SetText(total1.ToString(), richTextBox1);
            //};
            Task task2 = task1.ContinueWith(action);
        }

        //1. define a delegate with same signature as the crosss-threading handling
        // method (the SetText method)
        private delegate void RichTextBoxHandler(string s, RichTextBox rtb);
        private void SetText(string s, RichTextBox rtb)
        {
            if (rtb.InvokeRequired)
            {
                //create a delegate object
                RichTextBoxHandler handler = SetText;
                Invoke(handler, s, rtb);
            }
            else
            {
                rtb.AppendText(s + "\n");
                //scroll down
                rtb.ScrollToCaret();
            }
        }
    }
}
//Lab assignment:
//===============
//Use the same idea, but this time the method ComputeTotal... should take an int parameter
//that indicates the number of odd to add.
//Start such method in a task use the continueWith to display its return value in a second task

No comments:

Post a Comment