Title: Set video position with a scroll bar with WPF in C#
The example Control a video with the WPF MediaElement in C# lets you set video position in several ways. You can use the Next or Previous buttons to adjust the video's current position by 10 seconds. You can also enter a time in a text box and click Set Position to set video position to that time.
That example uses a ScrollBar to display the video's position. This example also lets you set video position by adjusting the ScrollBar.
Things can be confusing any time you use the same control for display (showing the video position) and control (adjusting video position). In this example, when the program updates the ScrollBar position to show progress, you don't want the ScrollBar to think the user has changed the control's value to set the position.
You also need to think about what you want the ScrollBar to do as the user adjusts it. For example, suppose you click and drag the ScrollBar thumb to set video position. While the user is dragging the thumb, do you want the video to continue running? If so, do you want to move the ScrollBar thumb to show its position? That works, but can be pretty confusing because the thumb won't stay beneath the mouse as the user drags it around. (You can try it on your own. It works but is annoying.)
For this example, I decided to stop playing the video whenever the user adjusts the ScrollBar position. That makes the program much simpler.
The following code shows the XAML code that defines the ScrollBar.
<ScrollBar Orientation="Horizontal" Grid.Row="1"
Name="sbarPosition" VerticalAlignment="Center"
Visibility="Hidden" Scroll="sbarPosition_Scroll"
PreviewMouseDown="sbarPosition_PreviewMouseDown"/>
The key changes to this code are the event handlers for the Scroll and PreviewMouseDown events.
The PreviewMouseDown event occurs when the user presses the mouse down on the control. You might think you should catch the MouseDown event instead, but that event occurs after the control has a chance to process the mouse event. Normally the control catches the mouse event, processes it, raises some higher-level event such as Scroll, and then discards the mouse event. That means the original mouse event is never raised to the level where your code can catch it.
This is the result of WPF's bubbling and tunneling event organization. The original mouse event "bubbles up" through the control hierarchy. At some point, the control catches it, raises its own event, and stops the bubbling event from continuing. If the event did continue, it would eventually "tunnel down" back through the control hierarchy.
Anyway, this example catches the control's PreviewMouseDown event so it can catch the mouse down event before it starts bubbling up and the ScrollBar can catch it. The following code shows the PreviewMouseDown event handler.
// Pause before the user moves the scroll bar.
private void sbarPosition_PreviewMouseDown(object sender,
MouseButtonEventArgs e)
{
minionPlayer.Pause();
EnableButtons(false);
}
This code pauses the MediaElement and then calls EnabledButtons to enable and disable buttons appropriately for when the video isn't playing.
The following code shows the ScrollBar control's Scroll event handler.
private void sbarPosition_Scroll(object sender,
System.Windows.Controls.Primitives.ScrollEventArgs e)
{
TimeSpan timespan = TimeSpan.FromSeconds(sbarPosition.Value);
minionPlayer.Position = timespan;
ShowPosition();
}
The ScrollBar value represents a number of seconds between 0 and the length of the video. This event handler converts the value into a TimeSpan and uses it to position the MediaElement. It then calls ShowPosition to update the text box that shows the elapsed number of seconds.
One potential issue fails to occur when the code updates the ScrollBar position. Here's the scenario: The user adjusts the ScrollBar, the ScrollBar calls ShowPosition, and ShowPosition sets the ScrollBar position. It would be bad if setting the position raised the Scroll event again so the code entered a loop. Fortunately setting the ScrollBar position in code doesn't raise the Scroll event so this isn't an issue.
Download the example to experiment with it and to see additional details.
|