locked
How to bind Slider position to Current ElementMedia time value ? RRS feed

  • Question

  • Dear all,

    I am playing a video in a MediaElement and I am looking for a simple thing.
    I have a Slider that is use as a Seek position on the video. The seek position works well but when the Video is playing, the seek position remains at position when I set it.

    I would like to retrive the current elapse time of the video then set the Maxvalue and Current value of my seek slider to reflect the media time .

    what is the efficeint way to do that ?

    regards

    serge


    Your knowledge is enhanced by that of others.


    Sunday, August 12, 2012 4:55 PM

Answers

  • I have not tried above code if it could work well, however, I think to complete silder and mediaelement position binding, the better method is create your own timer and update the silder value, there is a good sample shared by other MSFT:

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/4cf2c8c2-b536-45ef-bfa4-a9317c67f5ce

    MSDN document:
    http://msdn.microsoft.com/en-us/library/ms748248.aspx


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Sheldon _Xiao Friday, August 24, 2012 5:00 AM
    Monday, August 13, 2012 9:42 AM
  • Try this serge,

    <Window x:Class="Media.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="500" Width="525">
        <Grid>
            <StackPanel Orientation="Vertical">
                <MediaElement x:Name="MediaPlayer" Width="300" Height="300" Source="C:\Users\Public\Videos\Sample Videos\Wildlife.wmv" MediaOpened="MediaPlayer_MediaOpened"></MediaElement>
                <Slider x:Name="DurationSlider" Thumb.DragCompleted="DurationSlider_DragCompleted"></Slider>
                <TextBlock x:Name="Duration" Height="30" Text="TextBlock" TextAlignment="Center" FontWeight="ExtraBold" FontSize="18"/>
            </StackPanel>
        </Grid>
    </Window>
    

    Code Behind:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Threading;
    
    namespace Media
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public delegate void timerTick(); 
            DispatcherTimer ticks = new DispatcherTimer();
            timerTick tick; 
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void MediaPlayer_MediaOpened(object sender, RoutedEventArgs e)
            {
                DurationSlider.Minimum = 0;
                DurationSlider.Maximum = MediaPlayer.NaturalDuration.TimeSpan.TotalMilliseconds;
                //MediaPlayer.Position = new TimeSpan(0, 0, 0, 0, (int)DurationSlider.Value);
                ticks.Interval = TimeSpan.FromMilliseconds(1);
                ticks.Tick += ticks_Tick;
                tick = new timerTick(changeStatus);
                ticks.Start();
            }
    
    
            void ticks_Tick(object sender, object e)
            {
                Dispatcher.Invoke(tick);
            }
    
            void changeStatus()   
            {
                /* If you want the Slider to Update Regularly Just UnComment the Line Below*/
                //DurationSlider.Value = MediaPlayer.Position.TotalMilliseconds;
                Duration.Text = Milliseconds_to_Minute((long)MediaPlayer.Position.TotalMilliseconds); 
            }
    
            public string Milliseconds_to_Minute(long milliseconds)
            {
                int minute = (int)(milliseconds / (1000 * 60));
                int seconds = (int)(milliseconds / 1000);
                return (minute + " : " + seconds);
            }
    
            private void DurationSlider_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
            {
                /* Binds it to the Media Element */
                TimeSpan ts = new TimeSpan(0,0,0,0,(int)DurationSlider.Value);
                MediaPlayer.Position = ts;
            }     
        }
    }
    

    Happy Programming!!!

    • Marked as answer by Sheldon _Xiao Friday, August 24, 2012 5:00 AM
    Monday, August 13, 2012 11:36 AM
  • Hi Serge,

    I do not suggest you please 10 videos with 10 mediaelements at the same time as you said, becasue "At this time Microsoft only warrants four simultaneous instances of the WMP OCX control or WMP application per global user session", for detail explaination, refer to below part:

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/9fd599fa-6967-480d-9e7e-f72d3dee2e2e


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Sheldon _Xiao Friday, August 24, 2012 5:00 AM
    Tuesday, August 14, 2012 5:31 AM

All replies

  • Below is the code I use for a media app I created:

    <UserControl x:Class="MP3Player" x:Name="theMP3Player"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:NewMediaPlayer"
                 mc:Ignorable="d" 
                 d:DesignHeight="117" d:DesignWidth="468" Background="Transparent" Loaded="UserControl_Loaded" >
        <UserControl.Resources>
            <local:JustReturnTheSame x:Key="jts"></local:JustReturnTheSame>
            <local:EmptyIsHidden x:Key="eih"></local:EmptyIsHidden>
            <local:ColumnHiddenIfAllTheSame x:Key="chiats"></local:ColumnHiddenIfAllTheSame>
            
            <Style x:Key="tbBeige" TargetType="TextBlock" >
                <Setter Property="Foreground" Value="Beige"></Setter>
            </Style>
    
            <Style x:Key="NoButtonBorder" TargetType="{x:Type Button}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <ContentPresenter                  
                                Margin="{TemplateBinding Padding}"                  
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"                  
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"                  
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"                  
                                ContentTemplate="{TemplateBinding ContentTemplate}"                  
                                RecognizesAccessKey="True"                  
                                Content="{TemplateBinding Content}" />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
    
        </UserControl.Resources>
        <Grid>
            <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
                <StackPanel Orientation="Horizontal">
                    <!-- Ths slider shows the progress of the media. -->
                    <Slider Name="timelineSlider" Margin="0,5" Width="250"  HorizontalAlignment="Center" IsMoveToPointEnabled="True" 
                            Value="{Binding Path=tclock.CurrentTime.Milliseconds, Mode=OneWay}" ValueChanged="timelineSlider_ValueChanged" ToolTip="{Binding playDisplay}"
                            >
                    </Slider>
                    <Popup Name="TestPopup" IsOpen="False" Placement="MousePoint">
                        <TextBlock Background="Yellow" Width="140" TextWrapping="Wrap">
                            This is a popup with a PlacementRectangle.
                        </TextBlock>
                    </Popup>
                    <ComboBox x:Name="thePlayList" ItemsSource="{Binding songList}" ToolTip="Click to see playing song list" Visibility="{Binding songList,Converter={StaticResource eih}}" >
                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Width="30" Text="{Binding TrackNumber}" Style="{StaticResource tbBeige}" Background="Black"></TextBlock>
                                    <TextBlock Width="200" Text="{Binding Title}" Style="{StaticResource tbBeige}" Background="Black"></TextBlock>
                                    <TextBlock Width="200" Text="{Binding Artist}" Style="{StaticResource tbBeige}" Background="Black" 
                                               Visibility="{Binding ElementName=theMP3Player,Path=songList, Converter={StaticResource chiats}}"></TextBlock>
                                </StackPanel>
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>
                    <StackPanel  Orientation="Horizontal" >
                        <Image Height="24" Width="24" Source="{Binding cdDisplay}" Margin="0,0,8,0"></Image>
                        <TextBlock Text="{Binding isPlayingName}" Style="{StaticResource tbBeige}"></TextBlock>
                    </StackPanel>
                </StackPanel>
    
                <StackPanel DockPanel.Dock="Top"   x:Name="PlayerControls" Orientation="Horizontal" HorizontalAlignment="Center"  VerticalAlignment="Center"  >
    
                    <Button Style="{StaticResource NoButtonBorder}" x:Name="PreviousSong" Background="Transparent" IsEnabled="False" IsEnabledChanged="PreviousSong_IsEnabledChanged">
                        <StackPanel Orientation="Horizontal" >
                            <Image  Width="30" Height="30" ToolTip="Previous Song" Source="/NewMediaPlayer;component/Images/backward-48x48.png" />
                        </StackPanel>
                    </Button>
    
                    <Button Style="{StaticResource NoButtonBorder}" Background="Transparent" x:Name="butPlaySong" IsEnabled="False" IsEnabledChanged="PreviousSong_IsEnabledChanged">
                        <StackPanel Orientation="Horizontal" >
                            <Image  Width="30" Height="30" ToolTip="Play Song" Source="/NewMediaPlayer;component/Images/play-48x48.png" />
                        </StackPanel>
                    </Button>
    
                    <Button Style="{StaticResource NoButtonBorder}" Background="Transparent" x:Name="PauseSong" IsEnabled="False" IsEnabledChanged="PreviousSong_IsEnabledChanged">
                        <StackPanel Orientation="Horizontal" >
                            <Image  Width="30" Height="30" ToolTip="Pause Song" Source="/NewMediaPlayer;component/Images/pause-48x48.png" />
                        </StackPanel>
                    </Button>
    
                    <Button Style="{StaticResource NoButtonBorder}" Background="Transparent" x:Name="StopSong" IsEnabled="False" IsEnabledChanged="PreviousSong_IsEnabledChanged">
                        <StackPanel Orientation="Horizontal" >
                            <Image  Width="30" Height="30" ToolTip="Stop Song" Source="/NewMediaPlayer;component/Images/stop-song.png" />
                        </StackPanel>
                    </Button>
    
                    <Button Style="{StaticResource NoButtonBorder}" Background="Transparent" x:Name="NextSong" IsEnabled="False" IsEnabledChanged="PreviousSong_IsEnabledChanged">
                        <StackPanel Orientation="Horizontal" >
                            <Image  Width="30" Height="30" ToolTip="Next Song" Source="/NewMediaPlayer;component/Images/forward-48x48.png" />
                        </StackPanel>
                    </Button>
    
                    <TextBlock Style="{StaticResource tbBeige}" Width="75" Text="{Binding playDisplay}"></TextBlock>
    
                </StackPanel>
    
            </StackPanel>
            <MediaElement x:Name="theMedia" 
                          LoadedBehavior="Manual"  MediaOpened="theMedia_MediaOpened" MediaEnded="theMedia_MediaEnded">
            </MediaElement>
        </Grid>
    </UserControl>
    

    Hope this helps

    LS


    Lloyd Sheen

    • Proposed as answer by Pete LakerMVP Sunday, August 12, 2012 8:15 PM
    Sunday, August 12, 2012 6:21 PM
  • Sorry, bad finger so I missed the code behind:

        Private _tclock As MediaClock
        Public Property tclock() As MediaClock
            Get
                Return _tclock
            End Get
            Set(ByVal value As MediaClock)
                _tclock = value
                RaiseChanged("tclock")
            End Set
        End Property

    Private Sub theMedia_MediaOpened(sender As System.Object, e As System.Windows.RoutedEventArgs) Me.DataContext = Me timelineSlider.Maximum = theMedia.NaturalDuration.TimeSpan.TotalMilliseconds ti = New MediaTimeline(theMedia.Source) AddHandler ti.CurrentTimeInvalidated, AddressOf MediaTimeChanged tclock = ti.CreateClock() End Sub Private fromEvent As Boolean = False Private Sub MediaTimeChanged(ByVal sender As Object, ByVal e As EventArgs) fromEvent = True timelineSlider.Value = theMedia.Position.TotalMilliseconds RaiseChanged("playDisplay") fromEvent = False End Sub 'MediaTimeChanged



    Lloyd Sheen

    • Proposed as answer by Pete LakerMVP Sunday, August 12, 2012 8:15 PM
    Sunday, August 12, 2012 6:34 PM
  • Hello,

    I have try to implement your solution but when the video is playing now it is playing and stoping similar as when you have a really low internet connection.

    Did I miss something ?

    here is what I have :

    public partial class VideoViewControl : UserControl { bool IsMutePress = false; bool IsPlayPress = false; bool IsPausePress = false; bool IsStopPress = false; private DispatcherTimer _timer; private MediaTimeline _timeLine; public VideoViewControl() { InitializeComponent(); } private void OnChangeMediaVolume(object sender, RoutedPropertyChangedEventArgs<double> e) { vdoMedia.Volume = (double)volumeSlider.Value; } private void OnSeekToMediaPosition(object sender, RoutedPropertyChangedEventArgs<double> e) { int SliderValue = (int)timelineSlider.Value; // Overloaded constructor takes the arguments days, hours, minutes, seconds, miniseconds. // Create a TimeSpan with miliseconds equal to the slider value. TimeSpan ts = new TimeSpan(0, 0, 0, 0, SliderValue); vdoMedia.Position = ts; } private void buMute_Click(object sender, RoutedEventArgs e) { IsMutePress = !IsMutePress; if (IsMutePress) { buMute.Content = FindResource("VolumeMute"); vdoMedia.IsMuted = IsMutePress; //buMute.Foreground = new SolidColorBrush(Colors.DarkBlue); buMute.Background = FindResource("KnaufDarkGreyBlue") as SolidColorBrush; } else { buMute.Content = FindResource("Volume"); vdoMedia.IsMuted = IsMutePress; buMute.Background = new SolidColorBrush(Colors.Transparent); } } private void buStop_Click(object sender, RoutedEventArgs e) { IsStopPress = !IsStopPress; if (IsStopPress) { buStop.Background = FindResource("KnaufDarkGreyBlue") as SolidColorBrush; // The Stop method stops and resets the media to be played from // the beginning. vdoMedia.Stop(); } else { buStop.Background = new SolidColorBrush(Colors.Transparent); if (IsPlayPress) vdoMedia.Play(); } } private void buPause_Click(object sender, RoutedEventArgs e) { IsPausePress = !IsPausePress; if (IsPausePress) { buPause.Background = FindResource("KnaufDarkGreyBlue") as SolidColorBrush; // The Pause method pauses the media if it is currently running. // The Play method can be used to resume. vdoMedia.Pause(); } else { buPause.Background = new SolidColorBrush(Colors.Transparent); if (IsPlayPress) vdoMedia.Play(); } } private void buPlay_Click(object sender, RoutedEventArgs e) { IsPlayPress = !IsPlayPress; if (IsPlayPress) { buPlay.Background = FindResource("KnaufDarkGreyBlue") as SolidColorBrush; // The Play method will begin the media if it is not currently active or // resume media if it is paused. This has no effect if the media is // already running. vdoMedia.Play(); } else { buPlay.Background = new SolidColorBrush(Colors.Transparent); vdoMedia.Stop(); } } private void Element_MediaOpened(object sender, RoutedEventArgs e) { _timeLine = new MediaTimeline(vdoMedia.Source); _timeLine.CurrentTimeInvalidated+=new EventHandler(_timeLine_CurrentTimeInvalidated); MediaClockTime = _timeLine.CreateClock(); timelineSlider.Maximum = vdoMedia.NaturalDuration.TimeSpan.TotalMilliseconds; // Initialize the MediaElement property values. InitializePropertyValues(); } void _timeLine_CurrentTimeInvalidated(object sender, EventArgs e) { timelineSlider.Value = vdoMedia.Position.TotalMilliseconds; } void InitializePropertyValues() { // Set the media's starting Volume to the current value of the // its slider control. vdoMedia.Volume = (double)volumeSlider.Value; } private void vdoMedia_Loaded(object sender, RoutedEventArgs e) { // The Play method will begin the media if it is not currently active or // resume media if it is paused. This has no effect if the media is // already running. vdoMedia.Play(); } private MediaClock _tclock; public MediaClock MediaClockTime { get { return _tclock; } set { _tclock = value; OnPropertyChanged("MediaClockTime"); } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } } }

     

    I have notice that if I remove the line in the _timeLine_CurrentTimeInvalidated handler, then video play correctly but slider is not updated anymore.

    I think there is a mess up with the OnSeekToMediaPosition which is call when I move manually the sliderto a seek position. If I remove the update of the slider in this handler, videoplay well, slider position is bind correctly BUT I cannot not use the slider for manual seek

    Note that I am in my scenario, the Slider should be bind to media time value, but I am also using it as SeekTo function and should work as well

    Did I miss something ?


    Your knowledge is enhanced by that of others.



    Sunday, August 12, 2012 10:14 PM
  • If you look at my code for the _timeLine_CurrentTimeInvalidated method (different name in mine) , there is a flag set. This is used to prevent the problem you are seeing.

    LS


    Lloyd Sheen

    Sunday, August 12, 2012 11:14 PM
  • Yes I have seen that but where you are using that flag for test ?

    in slider change event ?


    Your knowledge is enhanced by that of others.


    Monday, August 13, 2012 9:07 AM
  • I have not tried above code if it could work well, however, I think to complete silder and mediaelement position binding, the better method is create your own timer and update the silder value, there is a good sample shared by other MSFT:

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/4cf2c8c2-b536-45ef-bfa4-a9317c67f5ce

    MSDN document:
    http://msdn.microsoft.com/en-us/library/ms748248.aspx


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Sheldon _Xiao Friday, August 24, 2012 5:00 AM
    Monday, August 13, 2012 9:42 AM
  • Try this serge,

    <Window x:Class="Media.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="500" Width="525">
        <Grid>
            <StackPanel Orientation="Vertical">
                <MediaElement x:Name="MediaPlayer" Width="300" Height="300" Source="C:\Users\Public\Videos\Sample Videos\Wildlife.wmv" MediaOpened="MediaPlayer_MediaOpened"></MediaElement>
                <Slider x:Name="DurationSlider" Thumb.DragCompleted="DurationSlider_DragCompleted"></Slider>
                <TextBlock x:Name="Duration" Height="30" Text="TextBlock" TextAlignment="Center" FontWeight="ExtraBold" FontSize="18"/>
            </StackPanel>
        </Grid>
    </Window>
    

    Code Behind:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Windows.Threading;
    
    namespace Media
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public delegate void timerTick(); 
            DispatcherTimer ticks = new DispatcherTimer();
            timerTick tick; 
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void MediaPlayer_MediaOpened(object sender, RoutedEventArgs e)
            {
                DurationSlider.Minimum = 0;
                DurationSlider.Maximum = MediaPlayer.NaturalDuration.TimeSpan.TotalMilliseconds;
                //MediaPlayer.Position = new TimeSpan(0, 0, 0, 0, (int)DurationSlider.Value);
                ticks.Interval = TimeSpan.FromMilliseconds(1);
                ticks.Tick += ticks_Tick;
                tick = new timerTick(changeStatus);
                ticks.Start();
            }
    
    
            void ticks_Tick(object sender, object e)
            {
                Dispatcher.Invoke(tick);
            }
    
            void changeStatus()   
            {
                /* If you want the Slider to Update Regularly Just UnComment the Line Below*/
                //DurationSlider.Value = MediaPlayer.Position.TotalMilliseconds;
                Duration.Text = Milliseconds_to_Minute((long)MediaPlayer.Position.TotalMilliseconds); 
            }
    
            public string Milliseconds_to_Minute(long milliseconds)
            {
                int minute = (int)(milliseconds / (1000 * 60));
                int seconds = (int)(milliseconds / 1000);
                return (minute + " : " + seconds);
            }
    
            private void DurationSlider_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
            {
                /* Binds it to the Media Element */
                TimeSpan ts = new TimeSpan(0,0,0,0,(int)DurationSlider.Value);
                MediaPlayer.Position = ts;
            }     
        }
    }
    

    Happy Programming!!!

    • Marked as answer by Sheldon _Xiao Friday, August 24, 2012 5:00 AM
    Monday, August 13, 2012 11:36 AM
  • I would do all of this via Binding.

    Bind the Slider element value to the media element current position.  Then Bind the MaxValue of the media element TotalTime.

    In order to do this you may need an event handler hooked into the media element's current position/frame.  If you do it this way the only other thing you may need to do is to write a converter to get the media elements type coverted to the slider value type of Int or double.  


    JP Cowboy Coders Unite!

    • Proposed as answer by Sheldon _Xiao Friday, August 24, 2012 5:01 AM
    Monday, August 13, 2012 5:21 PM
  • Thnaks to all of you.

    A comination of your different approach help me to setup my scenarios.

    One question still :

    My application should be able to play smoothly at least 10 videos at the same time. Does this duration time update could affect performance of videos when more than 1 is playing at the same time ?

    regards

    serge


    Your knowledge is enhanced by that of others.

    Monday, August 13, 2012 5:51 PM
  • Hi Serge,

    I do not suggest you please 10 videos with 10 mediaelements at the same time as you said, becasue "At this time Microsoft only warrants four simultaneous instances of the WMP OCX control or WMP application per global user session", for detail explaination, refer to below part:

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/9fd599fa-6967-480d-9e7e-f72d3dee2e2e


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Sheldon _Xiao Friday, August 24, 2012 5:00 AM
    Tuesday, August 14, 2012 5:31 AM
  • Hi Serge,
     
    I am marking your issue as "Answered", if you have new findings about your issue, please let me know.


    Best regards,


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, August 24, 2012 5:00 AM