Channels ▼
RSS

Tools

Your Own MP3 Duration Calculator: Part 2


Remember Last Folder

Programs that remember where the user left off are much nicer to use. The .NET Framework provides standard infrastructure to persist application settings and it's well integrated with Visual Studio (see Figure 6). I only use it to remember the last source folder, but it can be extended to store any number of things like the size and position of the main window, the selected items in the current session and more.

[Click image to view at full size]
Figure 6

There are several other issues you have to take into account when thinking about persistent application settings such as write access and shared settings between all users vs. per-user settings.

Once you figured it out, it is pretty easy to use application settings (especially in Visual Studio). You define your properties in the settings tab. Visual Studio takes care of adding two files: Settings.Designer.cs and Settings.cs. These files together define the sealed Settings class (via partial classes in each file) under the MP3DurationCalculator.Properties namespace. The Settings.Designer.cs file contains a static instance of the default settings and get/set properties for each setting:


//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.3603
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace MP3DurationCalculator.Properties {

    
 [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]

 internal sealed partial class Settings : 
   global::System.Configuration.ApplicationSettingsBase {
    private static Settings defaultInstance = ((Settings)
(global::System.Configuration.ApplicationSettingsBase.Synchronized(
        new Settings())));
    public static Settings Default {
       get { return defaultInstance; }
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
     public string InitialFolder {
      get { return ((string)(this["InitialFolder"])); }
       set { this["InitialFolder"] = value; }
    }
   }
}

The Settings.cs file contains optional event handlers you can implement to respond to a change in settings and to intercept the saving process:


namespace MP3DurationCalculator.Properties 
{
  // This class allows you to handle specific events on the settings class:
  // The SettingChanging event is raised before a setting's value is changed.
 //  The PropertyChanged event is raised after a setting's value is changed.
 //  The SettingsLoaded event is raised after the setting values are loaded.
 //  The SettingsSaving event is raised before the setting values are saved.
 internal sealed partial class Settings 
  {    
   public Settings() 
    {
      // To add event handlers for saving and changing settings, uncomment the 
       //lines below:
      //
      // this.SettingChanging += this.SettingChangingEventHandler;
      //
      // this.SettingsSaving += this.SettingsSavingEventHandler;
      //
   }
   private void SettingChangingEventHandler(
      object sender, 
      System.Configuration.SettingChangingEventArgs e) 
    {
     // Add code to handle the SettingChangingEvent event here.
    }
    private void SettingsSavingEventHandler(
      object sender,        System.ComponentModel.CancelEventArgs e) 
    {
     // Add code to handle the SettingsSaving event here.
   }
 }
}

MDC saves its settings in the OnExit method of the App class:


namespace MP3DurationCalculator
{
  public partial class App : Application
  {
    protected override void OnExit(ExitEventArgs e)
    {
      base.OnExit(e);
  MP3DurationCalculator.Properties.Settings.Default.Save();
    }
  }
}

When MDC is loaded the settings are loaded automatically and are available in the MainWindow constructor. If the initial folder doesn't exist than the user's MyMusic special folder is used as an initial folder:


  public partial class MainWindow : Window
  {
    public MainWindow()
    {
       ...
      var initialFolder = Properties.Settings.Default.InitialFolder;
      if (!Directory.Exists(initialFolder))
        initialFolder =  
             Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);
	   ...	
    }
   ... 
   }

Give Me More...

Liat was pleased with all the changes and new features, but with the food comes the appetite. Once the initial excitement over MDC 2.0 subsided Liat wanted more features:

  • Make CD from multiple source folders (will require merging of track_list.csv files)
  • A full-fledged media control bar: play, pause, stop
  • A seek bar that allows skipping and also displays the current position of the song
  • Maybe a little database to manage prepared CDs and mark songs that were used already.

I guess this is a good sign. There are only two types of programs: the programs that users complain about and the programs they don't use.

Conclusion

The .NET Framework and WPF are a superb platform for developing rich client applications. It is designed well and supports both enterprise-grade applications as well as small fun utilities like MDC. I was able to extend MDC with a significant amount of user-requested functionality with minimal changes to the XAML and the code. The separation between UI description and data binding in XAML and event handling in code works very well. I'm looking forward to explore WPF further in the future.


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