private static FrameworkElement RenderMediaPlayer()

in source/dotnet/Library/AdaptiveCards.Rendering.Wpf/AdaptiveMediaRenderer.cs [209:569]


        private static FrameworkElement RenderMediaPlayer(AdaptiveRenderContext context, AdaptiveMediaSource mediaSource, FrameworkElement uiMedia)
        {
            var uiMediaPlayer = new Grid();

            var mediaElement = new MediaElement()
            {
                Stretch = Stretch.Fill,
            };
            uiMediaPlayer.Children.Add(mediaElement);

            // Add some height to keep the controls (timeline panel + playback panel)
            if (!IsAudio(mediaSource))
            {
                uiMediaPlayer.MinHeight = _panelHeight * 2 + _childMargin * 4;
            }

            var uiControlPanel = new StackPanel()
            {
                VerticalAlignment = VerticalAlignment.Bottom,
                Background = _controlBackgroundColor,
            };

            #region Timeline Panel

            // Using Grid to stretch the timeline slider
            var uiTimelinePanel = new Grid()
            {
                HorizontalAlignment = HorizontalAlignment.Stretch,
                Height = _panelHeight,
            };

            TextBlock uiCurrentTime = new TextBlock()
            {
                Text = "00:00:00",
                Foreground = _controlForegroundColor,
                VerticalAlignment = VerticalAlignment.Center,
                Margin = _marginThickness,
            };
            uiTimelinePanel.ColumnDefinitions.Add(new ColumnDefinition()
            {
                Width = new GridLength(20, GridUnitType.Auto),
            });
            Grid.SetColumn(uiCurrentTime, 0);
            uiTimelinePanel.Children.Add(uiCurrentTime);

            Slider uiTimelineSlider = new Slider()
            {
                Margin = _marginThickness,
                IsEnabled = false,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Center,
            };
            uiTimelinePanel.ColumnDefinitions.Add(new ColumnDefinition()
            {
                Width = new GridLength(20, GridUnitType.Star),
            });
            Grid.SetColumn(uiTimelineSlider, 1);
            uiTimelinePanel.Children.Add(uiTimelineSlider);

            TextBlock uiMaxTime = new TextBlock()
            {
                Text = "00:00:00",
                Foreground = _controlForegroundColor,
                VerticalAlignment = VerticalAlignment.Center,
                Margin = _marginThickness,
            };
            uiTimelinePanel.ColumnDefinitions.Add(new ColumnDefinition()
            {
                Width = new GridLength(20, GridUnitType.Auto),
            });
            Grid.SetColumn(uiMaxTime, 2);
            uiTimelinePanel.Children.Add(uiMaxTime);

            #endregion

            uiControlPanel.Children.Add(uiTimelinePanel);

            #region Playback + Volume Panel

            var uiPlaybackVolumePanel = new Grid()
            {
                Height = _panelHeight,
            };

            #region Create Playback Control Container

            var uiPlaybackControlContainer = new StackPanel()
            {
                VerticalAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Left,
                Orientation = Orientation.Horizontal,
                Height = _panelHeight,
            };

            // Play trigger attached with the thumbnail button
            var playTrigger = new EventTrigger(UIElement.MouseUpEvent)
            {
                SourceName = "thumbnailButton",
            };

            var mediaTimeline = new MediaTimeline()
            {
                // This URI was previously confirmed to be valid
                Source = context.Config.ResolveFinalAbsoluteUri(mediaSource.Url),
            };
            Storyboard.SetTarget(mediaTimeline, mediaElement);

            var storyboard = new Storyboard()
            {
                SlipBehavior = SlipBehavior.Slip,
            };
            storyboard.Children.Add(mediaTimeline);
            var beginStoryboard = new BeginStoryboard()
            {
                // An arbitrary name is necessary for the storyboard to work correctly
                Name = "beginStoryboard",
                Storyboard = storyboard,
            };
            playTrigger.Actions.Add(beginStoryboard);

            // The play trigger needs to be added to uiMedia since
            // uiThumbnailButton is inside uiMedia
            uiMedia.Triggers.Add(playTrigger);

            // Buffering signal
            var uiBuffering = new TextBlock()
            {
                Text = "⏳ Buffering...",
                Foreground = _controlForegroundColor,
                VerticalAlignment = VerticalAlignment.Center,
                Margin = _marginThickness,
            };
            uiPlaybackControlContainer.Children.Add(uiBuffering);

            // Pause button
            var uiPauseButton = RenderPlaybackButton("⏸");
            uiPlaybackControlContainer.Children.Add(uiPauseButton);

            // Resume button
            var uiResumeButton = RenderPlaybackButton("⏵");
            uiPlaybackControlContainer.Children.Add(uiResumeButton);

            // Replay button
            var uiReplayButton = RenderPlaybackButton("🔄");
            uiPlaybackControlContainer.Children.Add(uiReplayButton);

            // Click events
            MediaState currentMediaState = MediaState.NotStarted;
            uiPauseButton.MouseUp += (sender, e) =>
            {
                storyboard.Pause(uiMedia);
                currentMediaState = MediaState.IsPaused;
                HandlePlaybackButtonVisibility(currentMediaState, uiPauseButton, uiResumeButton, uiReplayButton);
            };
            uiResumeButton.MouseUp += (sender, e) =>
            {
                storyboard.Resume(uiMedia);
                currentMediaState = MediaState.IsPlaying;
                HandlePlaybackButtonVisibility(currentMediaState, uiPauseButton, uiResumeButton, uiReplayButton);
            };

            #endregion

            // Add to control panel
            uiPlaybackVolumePanel.ColumnDefinitions.Add(new ColumnDefinition()
            {
                Width = new GridLength(20, GridUnitType.Star),
            });
            Grid.SetColumn(uiPlaybackControlContainer, 0);
            uiPlaybackVolumePanel.Children.Add(uiPlaybackControlContainer);

            #region Create Volume Control Container

            var uiVolumeControlContainer = new Grid()
            {
                Height = _panelHeight,
                VerticalAlignment = VerticalAlignment.Center,
            };

            // 2 overlapping buttons to alternate between mute/unmute states
            var uiVolumeMuteButton = new TextBlock()
            {
                Text = "🔊",
                FontFamily = _symbolFontFamily,
                FontSize = _childHeight,
                Foreground = _controlForegroundColor,
                Margin = _marginThickness,
                VerticalAlignment = VerticalAlignment.Center,
            };
            uiVolumeControlContainer.ColumnDefinitions.Add(new ColumnDefinition()
            {
                Width = new GridLength(20, GridUnitType.Auto),
            });
            Grid.SetColumn(uiVolumeMuteButton, 0);
            uiVolumeControlContainer.Children.Add(uiVolumeMuteButton);

            var uiVolumeUnmuteButton = new TextBlock()
            {
                Text = "🔇",
                FontFamily = _symbolFontFamily,
                FontSize = _childHeight,
                Foreground = _controlForegroundColor,
                Margin = _marginThickness,
                VerticalAlignment = VerticalAlignment.Center,
                Visibility = Visibility.Collapsed,
            };
            uiVolumeControlContainer.ColumnDefinitions.Add(new ColumnDefinition()
            {
                Width = new GridLength(20, GridUnitType.Auto),
            });
            Grid.SetColumn(uiVolumeUnmuteButton, 0);
            uiVolumeControlContainer.Children.Add(uiVolumeUnmuteButton);

            Slider uiVolumeSlider = new Slider()
            {
                Orientation = Orientation.Horizontal,
                VerticalAlignment = VerticalAlignment.Center,
                Width = 100,

                Minimum = 0,
                Maximum = 1,
                Value = 0.5,
            };
            uiVolumeControlContainer.ColumnDefinitions.Add(new ColumnDefinition()
            {
                Width = new GridLength(20, GridUnitType.Auto),
            });
            Grid.SetColumn(uiVolumeSlider, 1);
            uiVolumeControlContainer.Children.Add(uiVolumeSlider);

            // Initialize media volume to 0.5
            mediaElement.Volume = uiVolumeSlider.Value;

            // Volume control handlers
            void muteVolume(object sender, MouseEventArgs e)
            {
                uiVolumeMuteButton.Visibility = Visibility.Collapsed;
                uiVolumeUnmuteButton.Visibility = Visibility.Visible;
                mediaElement.Volume = 0;
            }
            void unmuteVolume(object sender, RoutedEventArgs e)
            {
                uiVolumeUnmuteButton.Visibility = Visibility.Collapsed;
                uiVolumeMuteButton.Visibility = Visibility.Visible;
                mediaElement.Volume = uiVolumeSlider.Value;
            }

            uiVolumeMuteButton.MouseUp += muteVolume;
            uiVolumeUnmuteButton.MouseUp += unmuteVolume;
            uiVolumeSlider.ValueChanged += unmuteVolume;

            #endregion

            // Add to control panel
            uiPlaybackVolumePanel.ColumnDefinitions.Add(new ColumnDefinition()
            {
                Width = new GridLength(20, GridUnitType.Auto),
            });
            Grid.SetColumn(uiVolumeControlContainer, 1);
            uiPlaybackVolumePanel.Children.Add(uiVolumeControlContainer);

            #endregion

            uiControlPanel.Children.Add(uiPlaybackVolumePanel);

            uiMediaPlayer.Children.Add(uiControlPanel);

            #region Other events

            void showControlPanel(object sender, MouseEventArgs e) { uiControlPanel.Visibility = Visibility.Visible; }
            void collapseControlPanel(object sender, MouseEventArgs e) { uiControlPanel.Visibility = Visibility.Collapsed; }
            void mediaStarted(object sender, RoutedEventArgs e)
            {
                // Playback button visibility
                currentMediaState = MediaState.IsPlaying;
                uiBuffering.Visibility = Visibility.Collapsed;
                HandlePlaybackButtonVisibility(currentMediaState, uiPauseButton, uiResumeButton, uiReplayButton);

                // Control panel visibility
                if (!IsAudio(mediaSource))
                {
                    // Hide when the video starts playing
                    uiControlPanel.Visibility = Visibility.Collapsed;

                    // Assign mouse hover events to avoid blocking the video
                    uiMediaPlayer.MouseEnter += showControlPanel;
                    uiMediaPlayer.MouseLeave += collapseControlPanel;
                }
            }
            void mediaEnded(object sender, EventArgs e)
            {
                // Playback button visibility
                currentMediaState = MediaState.NotStarted;
                HandlePlaybackButtonVisibility(currentMediaState, uiPauseButton, uiResumeButton, uiReplayButton);

                // Control panel visibility
                if (!IsAudio(mediaSource))
                {
                    // Show when the video is complete
                    uiControlPanel.Visibility = Visibility.Visible;

                    // Remove mouse hover events to always show controls
                    uiMediaPlayer.MouseEnter -= showControlPanel;
                    uiMediaPlayer.MouseLeave -= collapseControlPanel;
                }
            }

            mediaElement.MediaOpened += mediaStarted;
            storyboard.Completed += mediaEnded;
            uiReplayButton.MouseUp += (sender, e) =>
            {
                // Seek to beginning
                storyboard.Seek(uiMedia, new TimeSpan(0, 0, 0, 0, 0), TimeSeekOrigin.BeginTime);

                // And start the media as usual
                mediaStarted(sender, e);
            };

            // Timeline slider events
            mediaElement.MediaOpened += (sender, e) =>
            {
                uiTimelineSlider.Maximum = mediaElement.NaturalDuration.TimeSpan.TotalMilliseconds;
                uiTimelineSlider.IsEnabled = true;

                uiMaxTime.Text = mediaElement.NaturalDuration.TimeSpan.ToString(@"hh\:mm\:ss");
            };
            storyboard.CurrentTimeInvalidated += (sender, e) => {
                uiTimelineSlider.Value = mediaElement.Position.TotalMilliseconds;

                uiCurrentTime.Text = mediaElement.Position.ToString(@"hh\:mm\:ss");
            };

            // Thumb events
            uiTimelineSlider.AddHandler(Thumb.DragStartedEvent, new DragStartedEventHandler((sender, e) =>
            {
                storyboard.Pause(uiMedia);
            }));
            uiTimelineSlider.AddHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler((sender, e) =>
            {
                int sliderValue = (int)uiTimelineSlider.Value;

                TimeSpan selectedTimeSpan = new TimeSpan(0, 0, 0, 0, sliderValue);

                uiCurrentTime.Text = selectedTimeSpan.ToString(@"hh\:mm\:ss");
            }));
            uiTimelineSlider.AddHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler((sender, e) =>
            {
                int sliderValue = (int)uiTimelineSlider.Value;
                storyboard.Seek(uiMedia, new TimeSpan(0, 0, 0, 0, sliderValue), TimeSeekOrigin.BeginTime);

                // Only resume playing if it's in playing mode
                if (currentMediaState == MediaState.IsPlaying)
                {
                    storyboard.Resume(uiMedia);
                }
            }));

            #endregion

            return uiMediaPlayer;
        }