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;
}