Click here to Skip to main content
15,884,628 members
Articles / Desktop Programming / WPF

A simple WPF media player with media item list

Rate me:
Please Sign up or sign in to vote.
4.89/5 (58 votes)
13 Sep 2007CPOL4 min read 406.5K   20.1K   140  
A simple WPF media player with media item list.
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;


namespace WPF_Media_Player
{
    /// <summary>
    /// prvoides a media player with a track list and volume controls and rating system
    /// </summary>
    public partial class ucMediaPlayer : System.Windows.Controls.UserControl
    {
        #region Instance Fields
        private double mediaItemsWidth = -1;
        bool singleMode = false;
        private Dictionary<string, MediaItem> mediaItems = new Dictionary<string, MediaItem>();
        ToggleButton[] btnStars = new ToggleButton[5];
        #endregion
        #region Ctor
        public ucMediaPlayer()
        {
            InitializeComponent();

            sliderTime.IsEnabled = false;
            sliderVolume.IsEnabled = false;
            txtRating.Visibility = Visibility.Hidden;
        }
        #endregion
        #region Private methods
        /// <summary>
        /// save the media items
        /// </summary>
        private void lblSave_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (mediaItems.Count > 0)
            {
                System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog();
                sfd.Filter = "xml (*.xml)|*.xml";
                if (sfd.ShowDialog() != System.Windows.Forms.DialogResult.Cancel)
                {
                    string filename = sfd.FileName;
                    FileInfo f = new FileInfo(filename);
                    if (f.Extension.EndsWith(".xml"))
                    {
                            List<MediaItem> mediaList = new List<MediaItem>();
                            foreach (MediaItem mi in mediaItems.Values)
                                mediaList.Add(mi);
                            if (XmlHandler.WriteXmlFile(filename, mediaList))
                            {
                                MessageBox.Show("Sucessfully saved your items");
                            }
                    }
                    else
                    {
                        MessageBox.Show("Can only save to xml files", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                }
            }
            else
            {
                MessageBox.Show("There are no items to save");
            }
        }

        /// <summary>
        /// add extra media items from a saved file
        /// </summary>
        private void lblLoad_MouseDown(object sender, MouseButtonEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
            ofd.Filter = "xml (*.xml)|*.xml";
            if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.Cancel)
            {
                string filename = ofd.FileName;
                FileInfo f = new FileInfo(filename);
                if (f.Extension.EndsWith(".xml"))
                {
                    List<MediaItem> mediaList = XmlHandler.ReadXmlFile(filename);
                    if (mediaList.Count > 0)
                    {
                        foreach (MediaItem mi in mediaList)
                        {
                            if (!mediaItems.ContainsKey(mi.ItemUri))
                            {
                                mediaItems.Add(mi.ItemUri.Substring(mi.ItemUri.LastIndexOf(@"\") + 1), mi);
                                lstMediaItems.Items.Add(mi);
                            }
                        }
                        MessageBox.Show("Sucessfully added your items");
                    }
                    else
                    {
                        MessageBox.Show("There were no items found to add");
                    }
                }
                else
                {
                    MessageBox.Show("Can only open xml files", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        /// <summary>
        /// Clear all media items
        /// </summary>
        private void lblClear_MouseDown(object sender, MouseButtonEventArgs e)
        {
            lstMediaItems.Items.Clear();
        }

        /// <summary>
        /// Change to 3D media buttons
        /// </summary>
        private void lbl3D_MouseDown(object sender, MouseButtonEventArgs e)
        {
            // Get the selected Style from the Window's Resources.
            Style buttonStyle = this.FindResource("btn3DStyle") as Style;

            // Add the selected Style to the Window's Resources with the
            // resource key used by the Button.Style's DynamicResource reference.
            this.Resources["ButtonStyle"] = buttonStyle;
        }

        private void lblNormal_MouseDown(object sender, MouseButtonEventArgs e)
        {
            // Get the selected Style from the Window's Resources.
            Style buttonStyle = this.FindResource("VideoButton") as Style;

            // Add the selected Style to the Window's Resources with the
            // resource key used by the Button.Style's DynamicResource reference.
            this.Resources["ButtonStyle"] = buttonStyle;
        }

        /// <summary>
        /// set the rating to the current stars for the current media items
        /// </summary>
        private void btnStars_Click(object sender, RoutedEventArgs e)
        {
            int rating = 0;
            for (int i = 0; i < 5; i++)
            {
                rating += btnStars[i].IsChecked.Value ? 1 : 0;
            }
            string key = mediaPlayerMain.Source.AbsolutePath.Substring(mediaPlayerMain.Source.AbsolutePath.LastIndexOf(@"/")+1);
            mediaItems[key].ItemRating = rating;
        }

        /// <summary>
        /// Stop media when ended
        /// </summary>
        private void mediaPlayerMain_MediaEnded(object sender, RoutedEventArgs e)
        {
            mediaPlayerMain.Stop();
        }

        /// <summary>
        /// Initialise UI elements based on current media item
        /// </summary>
        private void mediaPlayerMain_MediaOpened(object sender, RoutedEventArgs e)
        {
            sliderTime.Maximum = mediaPlayerMain.NaturalDuration.TimeSpan.TotalMilliseconds;
            sliderTime.IsEnabled = mediaPlayerMain.IsLoaded;
            sliderVolume.IsEnabled = mediaPlayerMain.IsLoaded;
        }

        /// <summary>
        /// stop the media playing
        /// </summary>
        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            // The Stop method stops and resets the media to be played from
            // the beginning.
            mediaPlayerMain.Stop();
        }

        /// <summary>
        /// pause the media playing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnPause_Click(object sender, RoutedEventArgs e)
        {
            // The Pause method pauses the media if it is currently running.
            // The Play method can be used to resume.
            mediaPlayerMain.Pause();
        }

        /// <summary>
        /// play the media
        /// </summary>
        private void btnPlay_Click(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.
            mediaPlayerMain.Play();
            mediaPlayerMain.Volume = (double)sliderVolume.Value;
        }

        /// <summary>
        /// collapse/expand media items to take up entire grid row (so no media item list)
        /// </summary>
        private void btnMediaPlayerMain_Click(object sender, RoutedEventArgs e)
        {
            if (mediaPlayerBorder != null)
            {
                int col = Grid.GetColumn(mediaPlayerBorder);
                //work out which columns need to be resized in grid
                for (int indexCol = 0; indexCol < grdMain.ColumnDefinitions.Count; indexCol++)
                {
                    if (indexCol != col)
                    {
                        //grid column for media length animations
                        GridLengthAnimation gla = new GridLengthAnimation();
                        gla.From = new GridLength(singleMode ? 10 : mediaItemsWidth, GridUnitType.Pixel);
                        gla.To = new GridLength(singleMode ? mediaItemsWidth : 10, GridUnitType.Pixel);
                        gla.Duration = new TimeSpan(0, 0, 2);
                        grdMain.ColumnDefinitions[indexCol].BeginAnimation(ColumnDefinition.WidthProperty, gla);
                        //opacity (fade media items list)
                        DoubleAnimation hideShowOpacAnim = new DoubleAnimation();
                        hideShowOpacAnim.From = singleMode ? 0.0 : 1.0;
                        hideShowOpacAnim.To = singleMode ? 1.0 : 0.0;
                        hideShowOpacAnim.Duration = new Duration(TimeSpan.Parse("0:0:1"));
                        svMediaItems.BeginAnimation(ScrollViewer.OpacityProperty, hideShowOpacAnim);
                    }
                }
            }
            singleMode = !singleMode;            
        }

        /// <summary>
        /// reset selected index if one selected. Item style uses buttons, so user uses buttons
        /// rather than selected index
        /// </summary>
        private void lstMediaItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //dont want to use the listbox selected item/index. As the Item template is
            //a button for each listitem lets use the buttons click event
            lstMediaItems.SelectedIndex = -1;
        }

        /// <summary>
        /// initialise UI state
        /// </summary>
        private void ucMediaPlayer_Loaded(object sender, RoutedEventArgs e)
        {
            mediaItemsWidth = svMediaItems.Width;
            mediaPlayerBorder.Visibility = Visibility.Hidden;

            // Get the selected Style from the Window's Resources.
            Style buttonStyle = this.FindResource("btn3DStyle") as Style;

            // Add the selected Style to the Window's Resources with the
            // resource key used by the Button.Style's DynamicResource reference.
            this.Resources["ButtonStyle"] = buttonStyle;
        }

        /// <summary>
        /// seek media to position (x)
        /// </summary>
        private void SeekToMediaPosition(object sender, RoutedPropertyChangedEventArgs<double> args)
        {
            int SliderValue = (int)sliderTime.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);
            mediaPlayerMain.Position = ts;
        }

        /// <summary>
        /// change media volume to position (x)
        /// </summary>
        private void ChangeMediaVolume(object sender, RoutedPropertyChangedEventArgs<double> args)
        {
            mediaPlayerMain.Volume = (double)sliderVolume.Value;
        }

        /// <summary>
        /// create star buttons
        /// </summary>
        private void createStarButtons()
        {
            string key = mediaPlayerMain.Source.AbsolutePath.Substring(mediaPlayerMain.Source.AbsolutePath.LastIndexOf(@"/") + 1);
            int itemRating = mediaItems[key].ItemRating;

            starStack.Children.Clear();

            for (int i = 0; i < 5; i++)
            {
                btnStars[i] = new ToggleButton();
                btnStars[i].Width = 14;
                btnStars[i].Height = 20;
                btnStars[i].IsChecked = itemRating >= i+1;
                btnStars[i].Click += new RoutedEventHandler(btnStars_Click);
                btnStars[i].Checked += new RoutedEventHandler(btnStars_Checked);
                btnStars[i].Unchecked += new RoutedEventHandler(btnStars_Unchecked);
                btnStars[i].IsEnabled = false;
                addStarStyle(btnStars[i]);
            }
            btnStars[0].IsEnabled = true;

            //show the text only if the buttons were added successfully
            txtRating.Visibility = starStack.Children.Count > 0 ? Visibility.Visible : Visibility.Hidden;
        }

        /// <summary>
        /// work out which other stars can be checked
        /// </summary>
        private void btnStars_Checked(object sender, RoutedEventArgs e)
        {

            ToggleButton starButton = (ToggleButton)sender;
            int pos = -1;

            for (int i = 0; i < 5; i++)
            {
                if (btnStars[i].Equals(starButton))
                {
                    pos = i;
                }
            }

            //special case need to reset position 0 star, as it will still be enabled
            //from when the stars were created
            if (pos == 1)
                btnStars[0].IsEnabled = false;

            //only allow next consecutive starButton to be toggled
            //basically must be checked in order
            if (pos > -1 && pos < 4)
            {
                btnStars[pos].IsEnabled = false;
                btnStars[pos + 1].IsEnabled = true;
            }
        }

        /// <summary>
        /// work out which other stars can be Unchecked
        /// </summary>
        private void btnStars_Unchecked(object sender, RoutedEventArgs e)
        {
            ToggleButton starButton = (ToggleButton)sender;
            int pos = -1;

            for (int i = 0; i < 5; i++)
            {
                if (btnStars[i].Equals(starButton))
                {
                    pos = i;
                }
            }
            //only allow next consecutive starButton to be toggled
            //basically must be checked in order
            if (pos > 0 && pos < 5)
            {
                if( pos < 4)
                    btnStars[pos+1].IsEnabled = false;
                btnStars[pos].IsEnabled = true;
                btnStars[pos - 1].IsEnabled = true;
            }
        }

        /// <summary>
        /// add Style to star buttons
        /// </summary>
        private void addStarStyle(ToggleButton btnStar)
        {
            Style starStyle = this.Resources["StarToggleButton"] as Style; ;
            if (starStyle != null)
            {
                btnStar.Style = starStyle;
                starStack.Children.Add(btnStar);
            }
        }

        /// <summary>
        /// open new media item based on item clicked
        /// </summary>
        private void btnMediaItems_Clicked(object sender, RoutedEventArgs e)
        {
            Button b = sender as Button;
            MediaElement mel = b.Content as MediaElement;
            mediaPlayerMain.Source = null;
            mediaPlayerMain.Source = mel.Source;
            mediaPlayerBorder.Visibility = Visibility.Visible;
            mediaPlayerMain.Play();
            mediaPlayerMain.Volume = (double)sliderVolume.Value;
            createStarButtons();
        }

        /// <summary>
        /// clear media items list
        /// </summary>
        private void btnClearMediaList_Click(object sender, RoutedEventArgs e)
        {
            lstMediaItems.Items.Clear();
        }

        /// <summary>
        /// Handles Drop Event for Media Items.
        /// </summary>
        private void Media_Drop(object sender, DragEventArgs e)
        {
            string[] fileNames = e.Data.GetData(DataFormats.FileDrop, true) as string[];
            //keep a dictionary of added files
            foreach (string f in fileNames)
            {
                if (IsValidMediaItem(f))
                    mediaItems.Add(f.Substring(f.LastIndexOf(@"\")+1),new MediaItem(@f,0));
            }

            //now add to the list
            foreach (MediaItem mi in mediaItems.Values)
                lstMediaItems.Items.Add(mi);

            // Mark the event as handled, so the control's native Drop handler is not called.
            e.Handled = true;
        }

        /// <summary>
        /// check to see if dragged items are valid
        /// </summary>
        /// <returns>true if filename is valid</returns>
        private bool IsValidMediaItem(string filename)
        {
            bool isValid = false;
            string fileExtesion = filename.Substring(filename.LastIndexOf("."));
            foreach (string s in MediaItem.allowableMediaTypes)
            {
                if (s.Equals(fileExtesion, StringComparison.CurrentCultureIgnoreCase))
                    isValid = true;
            }
            return isValid;
        }
        #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 Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions