// 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;
using System.Collections.Specialized;
namespace SkinableVideoPlayer
{
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
BaseAddressCommand = new DelegateCommand(SetBaseAddress, CanSetBaseAddress);
GetListOfVideosCommand = new DelegateCommand(GetListOfVideos, CanGetListOfVideos);
SetMediaElementCommand = new DelegateCommand(SetMediaElement, CanSetMediaElement);
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);
}
// Commands
#region BaseAddressCommand
public ICommand BaseAddressCommand { get; set; }
public void SetBaseAddress(object param)
{
BaseAddressProperty = (string)param;
}
private bool CanSetBaseAddress(object param)
{
return true;
}
#endregion
#region GetListOfVideosCommand
public ICommand GetListOfVideosCommand { get; set; }
public void GetListOfVideos(object param)
{
LoadListOfVideos();
}
private bool CanGetListOfVideos(object param)
{
return true;
}
#endregion
#region SetMediaElementCommand
public ICommand SetMediaElementCommand { get; set; }
public void SetMediaElement(object param)
{
// Play Video
MediaElement parmMediaElement = (MediaElement)param;
MyMediaElement = parmMediaElement;
// Wire up an event to the MediaOpened Event
MyMediaElement.MediaOpened += new RoutedEventHandler(MyMediaElement_MediaOpened);
}
private bool CanSetMediaElement(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;
// Must have a MediaElement
if (MediaElementSet())
{
// Only allow Video to Play if it is not already Playing
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 (MediaElementSet())
{
// Only allow Video to Stop if it is already Playing
if (MyMediaElement.CurrentState == MediaElementState.Playing
|| (_Rewinding == true)
|| (_Forwarding == true))
{
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
{
// If FF or RW
if (_Rewinding || _Forwarding)
{
// Just turn off FF or RW
_Rewinding = false;
_Forwarding = false;
_InrementalValue = 3;
}
else
{
// The Media is not Playing
// And not FF or RW
// so we are Paused
// Play Video
MyMediaElement.Play();
progressTimer.Start();
}
}
}
private bool CanPauseVideo(object param)
{
bool CanPause = false;
if (MediaElementSet())
{
// 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}/Video/{1}", BaseAddressProperty, (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)
{
return MediaElementSet();
}
#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)
{
return MediaElementSet();
}
#endregion
// Events
#region MyMediaElement_MediaOpened
void MyMediaElement_MediaOpened(object sender, RoutedEventArgs e)
{
// Play Video
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);
}
#endregion
#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 LoadListOfVideos
private void LoadListOfVideos()
{
SilverlightVideos.GetVideos(BaseAddressProperty,(Param, EventArgs) =>
{
if (EventArgs.Error == null)
{
// loop thru each item
foreach (string Video in 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)
{
// Set the drop down to the first video
SelectedVideoInListProperty = 0;
// Set the virst Video to play
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");
if (_MediaBufferingProperty)
{
// Turn of any FF or RW
_Rewinding = false;
_Forwarding = false;
_InrementalValue = 3;
}
}
}
#endregion
#region MediaBufferingTimeProperty
private string _MediaBufferingTimeProperty;
public string MediaBufferingTimeProperty
{
get
{
return this._MediaBufferingTimeProperty;
}
set
{
this._MediaBufferingTimeProperty = value;
this.NotifyPropertyChanged("MediaBufferingTimeProperty");
}
}
#endregion
#region BaseAddressProperty
private string _BaseAddressProperty;
public string BaseAddressProperty
{
get
{
return this._BaseAddressProperty;
}
set
{
this._BaseAddressProperty = value;
this.NotifyPropertyChanged("BaseAddressProperty");
}
}
#endregion
// Collections
#region SilverlightVideoList
private ObservableCollection<String> _SilverlightVideoList = new ObservableCollection<string>();
public ObservableCollection<String> SilverlightVideoList
{
get { return _SilverlightVideoList; }
private set
{
_SilverlightVideoList = value;
this.NotifyPropertyChanged("SilverlightVideoList");
}
}
#endregion
// Utility
#region MediaElementSet
private bool MediaElementSet()
{
bool boolMediaElementSet = false;
if (MyMediaElement != null)
{
// Media must have the source set
if (MyMediaElement.Source != null)
{
boolMediaElementSet = true;
}
}
return boolMediaElementSet;
}
#endregion
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}