Click here to Skip to main content
15,896,912 members
Articles / Desktop Programming / XAML

Silverlight Advanced View Model Style Video Player

Rate me:
Please Sign up or sign in to vote.
4.91/5 (35 votes)
16 May 2010Ms-PL12 min read 83.8K   4K   48  
A full featured Silverlight View Model Style Video Player
// Copyright (c) 2010
// by OpenLight Group
// http://openlightgroup.net/
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
//
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.

using System;
using System.ComponentModel;
using System.Windows.Input;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Media;

namespace MVVMVideoPlayer_Test
{
    public class MainViewModel : INotifyPropertyChanged
    {
        private MediaElement MyMediaElement;
        private FrameworkElement SeekControl;
        private DispatcherTimer progressTimer;

        private bool _Rewinding = false;
        private bool _Forwarding = false;
        private Double _InrementalValue = 3;

        public MainViewModel()
        {
            // Set the command property
            MediaOpenedCommand = new DelegateCommand(MediaOpened, CanMediaOpened);
            PlayVideoCommand = new DelegateCommand(PlayVideo, CanPlayVideo);
			StopVideoCommand = new DelegateCommand(StopVideo, CanStopVideo);
            PauseVideoCommand = new DelegateCommand(PauseVideo, CanPauseVideo);
            SetSeekControlCommand = new DelegateCommand(SetSeekControl, CanSetSeekControl);
            SetVideoCommand = new DelegateCommand(SetVideo, CanSetVideo);
            SetFullScreenCommand = new DelegateCommand(SetFullScreen, CanSetFullScreen);
            ExitFullScreenCommand = new DelegateCommand(ExitFullScreen, CanExitFullScreen);
            RewindVideoCommand = new DelegateCommand(RewindVideo, CanRewindVideo);
            ForwardVideoCommand = new DelegateCommand(ForwardVideo, CanForwardVideo);

            // Call the Model to get the collection of Videos
            GetListOfVideos();
        }

       // Commands

        #region MediaOpenedCommand
        public ICommand MediaOpenedCommand { get; set; }
        public void MediaOpened(object param)
        {
            // Play Video
            MediaElement parmMediaElement = (MediaElement)param;
            MyMediaElement = parmMediaElement;
            TotalDurationProperty = MyMediaElement.NaturalDuration.TimeSpan.TotalSeconds;

            this.progressTimer = new DispatcherTimer();
            this.progressTimer.Interval = TimeSpan.FromSeconds(1);
            this.progressTimer.Tick += new EventHandler(this.ProgressTimer_Tick);

            SetCurrentPosition();

            // Play the video
            PlayVideo(null);
        }

        private bool CanMediaOpened(object param)
        {
            return true;
        }
        #endregion

        #region SetSeekControlCommand
        public ICommand SetSeekControlCommand { get; set; }
        public void SetSeekControl(object param)
        {
            // Hook Events into the Seek Control
            SeekControl = (FrameworkElement)param;
            SeekControl.MouseLeftButtonDown += new MouseButtonEventHandler(SeekControl_MouseLeftButtonDown);
        }

        private bool CanSetSeekControl(object param)
        {
            return true;
        }

        private void SeekControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            double position = e.GetPosition(SeekControl).X;
            double percent = position / SeekControl.ActualWidth;
            Seek(percent);
        }

        private void Seek(double percentComplete)
        {
            _Rewinding = false;
            _Forwarding = false;
            _InrementalValue = 3;

            TimeSpan duration = MyMediaElement.NaturalDuration.TimeSpan;
            int newPosition = (int)(duration.TotalSeconds * percentComplete);
            MyMediaElement.Position = new TimeSpan(0, 0, newPosition);
            SetCurrentPosition();
        }
        #endregion

        #region PlayVideoCommand
        public ICommand PlayVideoCommand { get; set; }
        public void PlayVideo(object param)
        {
            _Rewinding = false;
            _Forwarding = false;
            _InrementalValue = 3;

            // Play Video
            MyMediaElement.Play();
            progressTimer.Start();
        }

        private bool CanPlayVideo(object param)
        {
            bool CanPlay = false;
            // only allow Video to Play if it is not already Playing
            if (MyMediaElement != null)
            {
                if (MyMediaElement.CurrentState != MediaElementState.Playing)
                {
                    CanPlay = true;
                }
            }
            return CanPlay;
        }  
        #endregion

        #region StopVideoCommand
        public ICommand StopVideoCommand { get; set; }
        public void StopVideo(object param)
        {
            _Rewinding = false;
            _Forwarding = false;
            _InrementalValue = 3;

            // Stop Video
            MyMediaElement.Stop();
            progressTimer.Stop();
            SetCurrentPosition();
        }

        private bool CanStopVideo(object param)
        {
            bool CanStop = false;
            
            if (MyMediaElement != null)
            {
                CanStop = true;
            }

            return CanStop;
        }  
        #endregion

        #region PauseVideoCommand
        public ICommand PauseVideoCommand { get; set; }
        public void PauseVideo(object param)
        {
            // We only want to Pause if the media is Playing
            if (MyMediaElement.CurrentState == MediaElementState.Playing)
            {
                // If we can Pause the Video, Pause it
                if (MyMediaElement.CanPause)
                {
                    // Pause Video
                    MyMediaElement.Pause();
                }
                else
                {
                    // We can't pause the Video so Stop it
                    MyMediaElement.Stop();
                }

                if (progressTimer.IsEnabled)
                {
                    progressTimer.Stop();
                }
            }
            else
            {
                // The Media is not Playing so we are Paused
                // Play Video
                MyMediaElement.Play();
                progressTimer.Start();
            }

        }

        private bool CanPauseVideo(object param)
        {
            bool CanPause = false;

            _Rewinding = false;
            _Forwarding = false;
            _InrementalValue = 3;

            if (MyMediaElement != null)
            {
                // Only allow this Command if paused or Playing
                if ((MyMediaElement.CurrentState == MediaElementState.Paused)
                    || (MyMediaElement.CurrentState == MediaElementState.Playing))
                {
                    CanPause = true;
                }
            }

            return CanPause;
        }
        #endregion

        #region SetVideoCommand
        public ICommand SetVideoCommand { get; set; }
        public void SetVideo(object param)
        {
            _Rewinding = false;
            _Forwarding = false;
            _InrementalValue = 3;

            // Set Video
            string tmpSelectedVideo = string.Format(@"{0}/{1}", GetBaseAddress(), (String)param);
            SelectedVideoProperty = new Uri(tmpSelectedVideo, UriKind.RelativeOrAbsolute);

            // Stop Progress Timer
            if (progressTimer != null)
            {
                if (progressTimer.IsEnabled)
                {
                    progressTimer.Stop();
                }
            }
        }

        private bool CanSetVideo(object param)
        {
            // only set video if the parameter is not null
            return (param != null);
        }
        #endregion

        #region SetFullScreenCommand
        public ICommand SetFullScreenCommand { get; set; }
        public void SetFullScreen(object param)
        {
            if (MyMediaElement != null)
            {
                _Rewinding = false;
                _Forwarding = false;
                _InrementalValue = 3;

                // Put application in full screen mode
                var content = Application.Current.Host.Content;
                content.IsFullScreen = true;

                // Set the Video Brush to the content of the MediaElement
                VideoBrush objVideoBrush = new VideoBrush();
                objVideoBrush.SetSource(MyMediaElement);
                objVideoBrush.Stretch = Stretch.UniformToFill;

                // A Grid to show in full screen needs to be passed as the parameter
                // Set the background content of that panel to the VideoBrush

                // Note: Other elements and controls can be placed on this Grid
                // It does not have to be blank
                Grid objGrid = (Grid)param;
                objGrid.Visibility = Visibility.Visible;
                objGrid.Background = objVideoBrush;
            }
        }

        private bool CanSetFullScreen(object param)
        {
            // Only allow full screen if not in full screen
            var content = Application.Current.Host.Content;
            return (!content.IsFullScreen);
        }
        #endregion

        #region ExitFullScreenCommand
        public ICommand ExitFullScreenCommand { get; set; }
        public void ExitFullScreen(object param)
        {
            // A Panel to show in full screen needs to be passed as the parameter
            // Set this element to invisible
            Panel objPanel = (Panel)param;
            objPanel.Visibility = Visibility.Collapsed;
        }

        private bool CanExitFullScreen(object param)
        {
            // Only allow exit full screen if not in full screen
            // This may seem odd, but this command is being called by a SizeChanged event
            // If we ARE in full screen then we were actually just recently NOT in full screen
            // We only want to fire the ExitFullScreen if we were actually just In full screen
            // but NOT in full screen any more
            var content = Application.Current.Host.Content;
            return (!content.IsFullScreen);
        }
        #endregion

        #region RewindVideoCommand
        public ICommand RewindVideoCommand { get; set; }
        public void RewindVideo(object param)
        {
            if (_Forwarding)
            {
                _InrementalValue = 3;
            }

            _Rewinding = true;
            _Forwarding = false;
            MyMediaElement.Pause();

            _InrementalValue++;

            if (!progressTimer.IsEnabled)
            {
                progressTimer.Start();
            }
        }

        private bool CanRewindVideo(object param)
        {
            bool CanRewind = false;

            if (MyMediaElement != null)
            {
                CanRewind = true;
            }

            return CanRewind;
        }
        #endregion

        #region ForwardVideoCommand
        public ICommand ForwardVideoCommand { get; set; }
        public void ForwardVideo(object param)
        {
            if (_Rewinding)
            {
                _InrementalValue = 3;
            }

            _Rewinding = false;
            _Forwarding = true;
            MyMediaElement.Pause();

            _InrementalValue++;

            if (!progressTimer.IsEnabled)
            {
                progressTimer.Start();
            }
        }

        private bool CanForwardVideo(object param)
        {
            bool CanForward = false;

            if (MyMediaElement != null)
            {
                CanForward = true;
            }

            return CanForward;
        }
        #endregion

        // Events

        #region Time display
        private void ProgressTimer_Tick(object sender, EventArgs e)
        {
            if (_Rewinding || _Forwarding)
            {
                int newPosition = (int)(MyMediaElement.Position.TotalSeconds);

                if (_Rewinding)
                {
                    newPosition = (int)(newPosition - _InrementalValue);
                }

                if (_Forwarding)
                {
                    newPosition = (int)(newPosition + _InrementalValue);
                }

                MyMediaElement.Position = new TimeSpan(0, 0, newPosition);
            }

            SetCurrentPosition();
        }

        private void SetCurrentPosition()
        {
            // If the Media play is complete stop the media
            if (CurrentPositionProperty > 0)
            {
                if (CurrentPositionProperty >= TotalDurationProperty)
                {
                    // If in full screen mode - exit full screen mode
                    var content = Application.Current.Host.Content;
                    if (content.IsFullScreen)
                    {
                        content.IsFullScreen = false;
                    }

                    CurrentPositionProperty = 0;
                    StopVideo(null);
                }
            }
            else
            {
                if (CurrentPositionProperty < 0)
                {
                    // If in full screen mode - exit full screen mode
                    var content = Application.Current.Host.Content;
                    if (content.IsFullScreen)
                    {
                        content.IsFullScreen = false;
                    }

                    CurrentPositionProperty = 0;
                    StopVideo(null);
                }
            }

            // Update the time text e.g. 01:50 / 03:30
            CurrentProgressProperty = string.Format(
                "{0}:{1} / {2}:{3}",
                Math.Floor(MyMediaElement.Position.TotalMinutes).ToString("00"),
                MyMediaElement.Position.Seconds.ToString("00"),
                Math.Floor(MyMediaElement.NaturalDuration.TimeSpan.TotalMinutes).ToString("00"),
                MyMediaElement.NaturalDuration.TimeSpan.Seconds.ToString("00"));

            CurrentPositionProperty = MyMediaElement.Position.TotalSeconds;
            MediaBufferingProperty = (MyMediaElement.CurrentState == MediaElementState.Buffering);
            MediaBufferingTimeProperty = String.Format("Buffering {0} %", (MyMediaElement.BufferingProgress * 100).ToString("##"));
        }
        #endregion

        #region GetListOfVideos
        private void GetListOfVideos()
        {
            // Call the Model to get the collection of Videos
            SilverlightVideos.GetVideos().Subscribe(p =>
            {
                if (p.EventArgs.Error == null)
                {
                    // loop thru each item
                    foreach (string Video in p.EventArgs.Result)
                    {
                        // Add to the SilverlightVideoList collection
                        SilverlightVideoList.Add(Video);
                    }

                    // if we have any videos, set the selected item value to the first one
                    if (SilverlightVideoList.Count > 0)
                    {
                        SelectedVideoInListProperty = 0;
                        SetVideo(SilverlightVideoList[0]);
                    }
                }
            });
        }
        #endregion

        // Properties

        #region SelectedVideoProperty
        private Uri _SelectedVideoProperty;
        public Uri SelectedVideoProperty
        {
            get
            {
                return this._SelectedVideoProperty;
            }
            set
            {
                this._SelectedVideoProperty = value;
                this.NotifyPropertyChanged("SelectedVideoProperty");
            }
        } 
        #endregion

        #region CurrentProgressProperty
        private string _CurrentProgressProperty;
        public string CurrentProgressProperty
        {
            get
            {
                return this._CurrentProgressProperty;
            }
            set
            {
                this._CurrentProgressProperty = value;
                this.NotifyPropertyChanged("CurrentProgressProperty");
            }
        }
        #endregion

        #region TotalDurationProperty
        private double _TotalDurationProperty;
        public double TotalDurationProperty
        {
            get
            {
                return this._TotalDurationProperty;
            }
            set
            {
                this._TotalDurationProperty = value;
                this.NotifyPropertyChanged("TotalDurationProperty");
            }
        }
        #endregion

        #region CurrentPositionProperty
        private double _CurrentPositionProperty;
        public double CurrentPositionProperty
        {
            get
            {
                return this._CurrentPositionProperty;
            }
            set
            {
                this._CurrentPositionProperty = value;
                this.NotifyPropertyChanged("CurrentPositionProperty");
            }
        }
        #endregion

        #region SelectedVideoInListProperty
        private int _SelectedVideoInListProperty = -1;
        public int SelectedVideoInListProperty
        {
            get
            {
                return this._SelectedVideoInListProperty;
            }
            set
            {
                this._SelectedVideoInListProperty = value;
                this.NotifyPropertyChanged("SelectedVideoInListProperty");
            }
        }
        #endregion

        #region MediaBufferingProperty
        private bool _MediaBufferingProperty;
        public bool MediaBufferingProperty
        {
            get
            {
                return this._MediaBufferingProperty;
            }
            set
            {
                this._MediaBufferingProperty = value;
                this.NotifyPropertyChanged("MediaBufferingProperty");
            }
        }
        #endregion

        #region MediaBufferingTimeProperty
        private string _MediaBufferingTimeProperty;
        public string MediaBufferingTimeProperty
        {
            get
            {
                return this._MediaBufferingTimeProperty;
            }
            set
            {
                this._MediaBufferingTimeProperty = value;
                this.NotifyPropertyChanged("MediaBufferingTimeProperty");
            }
        }
        #endregion

        // Collections

        #region SilverlightVideoList
        private ObservableCollection<String> _SilverlightVideoList = new ObservableCollection<string>();
        public ObservableCollection<String> SilverlightVideoList
        {
            get { return _SilverlightVideoList; }
            private set
            {
                if (SilverlightVideoList == value)
                {
                    return;
                }

                _SilverlightVideoList = value;
                this.NotifyPropertyChanged("SilverlightVideoList");
            }
        }
        #endregion

        // Utility
		
	    #region GetBaseAddress
        private string GetBaseAddress()
        {
            string strXapFile = @"/ClientBin/MVVMVideoPlayer_Test.xap";

            string strBaseWebAddress =
                App.Current.Host.Source.AbsoluteUri.Replace(strXapFile, "");

            return string.Format(@"{0}/{1}", strBaseWebAddress, @"Video");
        }
        #endregion
    
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion
        
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Software Developer (Senior) http://ADefWebserver.com
United States United States
Michael Washington is a Microsoft MVP. He is a ASP.NET and
C# programmer.
He is the founder of
AiHelpWebsite.com,
LightSwitchHelpWebsite.com, and
HoloLensHelpWebsite.com.

He has a son, Zachary and resides in Los Angeles with his wife Valerie.

He is the Author of:

Comments and Discussions