Enhanced scheduler to support task instrumentation

Background
-----
During transition to ```DynamoScheduler``` the following are omitted:

1. Execution event notification through ```ExecutionEvents```
2. Instrumentation for graph update duration

This pull request is meant to provide a generalized way to re-enable these features through ```DynamoScheduler```.

Changes
-----
To re-enable the above features, the following changes are made to the scheduler infrastructure:

1. ```DynamoScheduler``` now exposes a new event: ```TaskStateChanged```. This event is raised when the state of an ```AsyncTask``` is changed. See below for possible state changes. The ```TaskStateChanged``` is currently handled by the owning ```DynamoModel```.

2. ```TaskStateChangedEventArgs``` event argument class is introduced for use in conjunction with ```DynamoScheduler.TaskStateChanged``` event. The class carries information about an ```AsyncTask``` object when its state changes. The state can be either one of the following values:

  - ```Scheduled``` (the task is scheduled)
  - ```Discarded``` (the task is discarded when task queue is compacted)
  - ```ExecutionStarting``` (```AsyncTask.ExecuteCore``` is about to be called)
  - ```ExecutionFailed``` (an exception is thrown from ```ExecuteCore``` method)
  - ```ExecutionCompleted``` (the call to ```ExecuteCore``` successfully returns)
  - ```CompletionHandled``` (the ```AsyncTask.HandleTaskCompletion``` successfully returns)

3. ```DynamoModel.OnAsyncTaskStateChanged``` method is introduced to handle ```DynamoScheduler.TaskStateChanged``` event. It currently calls ```LogAnonymousTimedEvent``` to record execution time when an ```UpdateGraphAsyncTask``` completes. The method also sends out ```OnGraphPreExecution``` and ```OnGraphPostExecution``` execution events.

4. ```DynamoScheduler``` used to make a call to ```AsyncTask.Execute``` method, handles the exception thrown from it, and then handle this exception over to ```AsyncTask.HandleTaskCompletion``` method. This is now changed. The ```AsyncTask.Execute``` method internally handles exception thrown from ```ExecuteCore``` method, so that it can set the ```AsyncTask.ExecutionEndTime``` property.

Unit tests
-----
1. The failing test case due to scheduler, ```TestPreAndPostExec```, is now passing and re-enabled.

2. A new test case ```TestTaskStateChangedEventHandling``` is introduced to verify all events sent out by ```DynamoScheduler```.

Note to reviewer
-----
Hi @lukechurch, these functionalities seem to be crucial to the release, please have a look. If all goes well I'll phase these into release branches. Thanks!