private async Task ChangeMission(string mission)
        {
            // Stop animating the current mission
            _animationTimer.Stop();

            // Get mission data
            _missionData = GetMissionData(mission);

            // Draw mission route on the inset
            // Create a collection of points to hold the mission
            PointCollection points = new PointCollection(SpatialReferences.Wgs84);

            // Add all of the points from the mission to the point collection
            points.AddPoints(_missionData.Select(m => m.ToMapPoint()));
            // Create a polyline to symbolize the route from the point collection
            Polyline route = new Polyline(points);

            // Update the route graphic's geometry with the newly created route polyline
            _routeGraphic.Geometry = route;
            // Update the inset map's scale
            await InsetMapView.SetViewpointScaleAsync(100000);

            // Update animation parameters
            _frameCount = _missionData.Length;
            _keyframe   = 0;

            // Set the MissionPlayPause button back to the currently 'playing' state
            MissionPlayPause.Content = "Pause";

            // Restart the animation
            _animationTimer.Start();
        }
        private bool AnimatePlane()
        {
            // Skip doing anything if animation is paused
            if (!_animationTimer)
            {
                return(true);
            }

            // Get the next position; % prevents going out of bounds even if the keyframe value is
            //     changed unexpectedly (e.g. due to user interaction with the progress slider).
            MissionFrame currentFrame = _missionData[_keyframe % _frameCount];

            // Update the UI
            double missionProgress = _keyframe / (double)_frameCount;

            // This is needed because the event could be running on a non-UI thread
            Device.BeginInvokeOnMainThread(() =>
            {
                // Update the progress slider; temporarily remove event subscription to avoid feedback loop
                MissionProgressBar.ValueChanged -= MissionProgressOnSeek;
                MissionProgressBar.Value         = missionProgress * 100;
                MissionProgressBar.ValueChanged += MissionProgressOnSeek;

                // Update stats display
                AltitudeLabel.Text = currentFrame.Elevation.ToString("F");
                HeadingLabel.Text  = currentFrame.Heading.ToString("F");
                PitchLabel.Text    = currentFrame.Pitch.ToString("F");
                RollLabel.Text     = currentFrame.Roll.ToString("F");
            });

            // Update plane's position
            _plane3D.Geometry = currentFrame.ToMapPoint();
            _plane3D.Attributes["HEADING"] = currentFrame.Heading;
            _plane3D.Attributes["PITCH"]   = currentFrame.Pitch;
            _plane3D.Attributes["ROLL"]    = currentFrame.Roll;

            // Update the inset map; plane symbol position
            _plane2D.Geometry = currentFrame.ToMapPoint();
            // Update inset's viewpoint and heading
            Viewpoint vp = new Viewpoint(currentFrame.ToMapPoint(), InsetMapView.MapScale,
                                         360 + (float)currentFrame.Heading);

            InsetMapView.SetViewpoint(vp);

            // Update the keyframe. This advances the animation
            _keyframe++;

            // Restart the animation if it has finished
            if (_keyframe >= _frameCount)
            {
                _keyframe = 0;
            }

            // Keep the animation event going
            return(true);
        }
        private async void AnimatePlane(object sender, object elapsedEventArgs)
        {
            // Get the next position; % prevents going out of bounds even if the keyframe value is
            //     changed unexpectedly (e.g. due to user interaction with the progress slider).
            MissionFrame currentFrame = _missionData[_keyframe % _frameCount];

            // Update the UI
            double missionProgress = _keyframe / (double)_frameCount;

            // This is needed because the event could be running on a non-UI thread
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                // Update the progress slider
                MissionProgressBar.Value = missionProgress;

                // Update stats display
                AltitudeTextBlock.Text = $"{currentFrame.Elevation:F}m";
                HeadingTextBlock.Text  = $"{currentFrame.Heading:F}\u00B0";
                PitchTextBlock.Text    = $"{currentFrame.Pitch:F}\u00B0";
                RollTextBlock.Text     = $"{currentFrame.Roll:F}\u00B0";
            });

            // Update plane's position
            _plane3D.Geometry = currentFrame.ToMapPoint();
            _plane3D.Attributes["HEADING"] = currentFrame.Heading;
            _plane3D.Attributes["PITCH"]   = currentFrame.Pitch;
            _plane3D.Attributes["ROLL"]    = currentFrame.Roll;

            // Update the inset map; plane symbol position
            _plane2D.Geometry = currentFrame.ToMapPoint();
            // Update inset's viewpoint and heading
            Viewpoint vp = new Viewpoint(currentFrame.ToMapPoint(), InsetMapView.MapScale,
                                         360 + (float)currentFrame.Heading);

            InsetMapView.SetViewpoint(vp);

            // Update the keyframe. This advances the animation
            _keyframe++;

            // Restart the animation if it has finished
            if (_keyframe >= _frameCount)
            {
                _keyframe = 0;
            }
        }
        private void AnimatePlane(object sender, ElapsedEventArgs elapsedEventArgs)
        {
            // Get the next position; % prevents going out of bounds even if the keyframe value is
            //     changed unexpectedly (e.g. due to user interaction with the progress slider).
            MissionFrame currentFrame = _missionData[_keyframe % _frameCount];

            // Update the UI
            double missionProgress = _keyframe / (double)_frameCount;

            // This is needed because the event could be running on a non-UI thread
            Dispatcher.BeginInvoke(new Action(() =>
            {
                // Update the progress slider
                MissionProgressBar.Value = missionProgress;

                // Update stats display
                AltitudeLabel.Text = currentFrame.Elevation.ToString("F") + "m";
                HeadingLabel.Text  = currentFrame.Heading.ToString("F") + "бу";
                PitchLabel.Text    = currentFrame.Pitch.ToString("F") + "бу";
                RollLabel.Text     = currentFrame.Roll.ToString("F") + "бу";
            }));

            // Update plane's position
            _plane3D.Geometry = currentFrame.ToMapPoint();
            _plane3D.Attributes["HEADING"] = currentFrame.Heading;
            _plane3D.Attributes["PITCH"]   = currentFrame.Pitch;
            _plane3D.Attributes["ROLL"]    = currentFrame.Roll;

            // Update the inset map; plane symbol position
            _plane2D.Geometry = currentFrame.ToMapPoint();
            // Update inset's viewpoint and heading
            Viewpoint vp = new Viewpoint(currentFrame.ToMapPoint(), InsetMapView.MapScale,
                                         360 + (float)currentFrame.Heading);

            InsetMapView.SetViewpoint(vp);

            // Update the keyframe. This advances the animation
            _keyframe++;

            // Restart the animation if it has finished
            if (_keyframe >= _frameCount)
            {
                _keyframe = 0;
            }
        }