Channels ▼
RSS

.NET

Your Own MP3 Duration Calculator: Part 2


Show the number of selected songs

This was another trivial request, but it required some code changes. The "status" text box display various status messages during the lifetime of the application (I probably should add a status bar for that). In theory, I could have a status object bound to the "status" text box, but that seemed like an overkill just for changing the contents of a text box every now and then (you would still need to update the status object from code). The number of selected songs should be displayed in two separate cases. The first one is when the collection of tracking info is complete. During the collection process the user may select already collected songs and view their total duration, but the status text box displays the progress of the collection process. Once the collection is complete it makes sense to display the current number of selected songs. The second case is of course when the number of selected songs is changed. The code is just two lines so I didn't even bother with a special method to update the status and just used the two-liner in both places. I use String.Format() to construct the message. Here is the first usage in onTrackInfo() when there are no more tracks:


  void onTrackInfo(TrackInfo ti)
 {
   if (ti == null)
   {
     // Update the status line
     var st = String.Format("{0}/{1} files are selected",
                            files.SelectedItems.Count,
                            _fileCount);
     status.Text = st;
      ...
   }
    ...
  }

The second usage is in the selectionChanged event handler of the files list view:


  void files_SelectionChanged(object sender, SelectionChangedEventArgs e)

 {
    ...
   // Update the status line
   var st = String.Format("{0}/{1} files are selected",
                          files.SelectedItems.Count,
                          _fileCount);
   status.Text = st;
    ...
  }

Play songs from within MDC

Okay, here is a feature with some substance. The media element is fully capable of playing tracks and we have one already in our main window. However, it is not a good idea to reuse the same media element used for collecting track info for playing tracks because I want the user to be able to play tracks during the collection process. This is a very important feature because the collection process can long seconds an even minutes if a folder contains hundreds of tracks. Another dedicated media element for playing songs solves the problem. Note that the media element I use for collecting track info doesn't interfere with the player media element because it never tries to play anything. It just opens each file, extracts the duration and closes the file.

I decided to go with a very spartan interface where you start and stop playing a song by right clicking with the mouse of a song. There is no way to pause or skip ahead and no way to see how far you are into the current song.

The act of playing a song doesn't change its selection state. You may play selected or unselected songs, during and after the collection process.

The player media element is an invisible element because it just plays audio in this case so it can be placed anywhere. I placed it next to the original media element in the Grid container of the main window:


<Grid>
    <MediaElement 
        Height="0" 
        Width="0" 
        Name="mediaElement" 
        LoadedBehavior="Manual" 
     />
    <MediaElement 
        Height="0" 
        Width="0" 
        Name="player" 
        LoadedBehavior="Manual" 
     />
     ...
   </Grid>

The code to enable play/stop is simple. It is all located in the event handler for the PreviewMouseRightButtionDown. WPF uses routed events. Routed events travel through the control hierarchy and any control along the way can handle the event and then it will not be passed further. There are two types of routed events: tunneling events and bubbling events. Tunneling events travel form parent to child and allow the parent to handle the event on behalf of many children or do some global handling and then let the children process them further. Bubbling events start at the child and bubble up to parents. The routed events travel in pairs. First, there is a tunneling event called PreviewXXX followed by a bubbling event called XXX. If some control handled the tunneling event the bubbling event will NOT be fired. So, the PreviewMouseRightButtonDown event is a tunneling event that's fired when the user clicks the right mouse button on the files list view. The main window is the parent of the list view so it gets first shot at handling it. Immediately sets the Handled property to true so the list view will never get a chance to process it. The reason is that the right mouse button click will toggle the selection if allowed to rich the list view. This is a behavior I want to suppress. Next, there is a somewhat complex check to find the parent of the original source of the right mouse click and see if it's a GridViewRowPresenter. If this check succeeds it means that the right click was indeed on one of songs in the list and not just a click in an empty area. Of course that's when we want to play or stop the current song. First, I need to figure out the path to the song file, which I retrieve from the clicked item. Note that the Content property of the clicked item is a TrackInfo object.

Then, I stop the player in case it was playing (it may be stopped but it causes no harm). If the player Source property is null (no song) or different then the current clicked item then I set the Source property to the new song and starts playing. Otherwise (clicked on the same playing stop) I set the Source to null for cleanup purposes.


    private void files_PreviewMouseRightButtonDown(object sender,
                                               MouseButtonEventArgs e)
    {
      e.Handled = true;
      var x = ((FrameworkElement)e.OriginalSource).Parent;
      if (x is GridViewRowPresenter)
      {
        var ti = ((GridViewRowPresenter)x).Content as TrackInfo;
        string path = System.IO.Path.Combine(tbTargetFolder.Text, ti.Name);
        player.Stop();
        if (player.Source == null || player.Source.AbsolutePath != path)
        {
          player.Source = new System.Uri(path);
          player.Play();
        }
        else
        {
          player.Source = null;
        }
      }
    }


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video