Classic JukeBox
- Posted: May 19, 2009 at 9:09 AM
- 1,858 Views
- 2 Comments
Loading User Information from Channel 9
Something went wrong getting user information from Channel 9
Loading User Information from MSDN
Something went wrong getting user information from MSDN
Loading Visual Studio Achievements
Something went wrong getting the Visual Studio Achievements
Remember the
classic arcade style jukeboxes? Today we will be creating our own jukebox using WPF, WMP, a little bit of 3D, some very basic electronics (costing less than $10 USD) and a splash of M-V-VM
A couple of weeks ago I took my son to the game arcade to play a little… while playing, I noticed in the corner a old jukebox… I started wondering how difficult it would be to recreate one of these using “real” hardware and WPF? This article explorers how to make real hardware control software applications in a practical manner
“Once a developer becomes comfortable with WPF and MVVM, it can be difficult to differentiate the two. MVVM is the lingua franca of WPF developers because it is well suited to the WPF platform, and WPF was designed to make it easy to build applications using the MVVM pattern (amongst others). In fact, Microsoft was using MVVM internally to develop WPF applications, such as Microsoft Expression Blend, while the core WPF platform was under construction. Many aspects of WPF, such as the look-less control model and data templates, utilize the strong separation of display from state and behavior promoted by MVVM.”
WPF Apps With The Model-View-ViewModel Design Pattern by Josh Smith
The M-V-VM pattern helps to separate the logic from the UI which is VERY important when you actually want to manipulate the logic from external sources (Like real push buttons). Our MediaViewModel is extremely simple…
The MediaViewModel has a collection of albums (Which gets fetched when Initialize() is called) and also exposes some commands
Ensure that your Windows Media Player (WMP) media library has some media. I added a few albums to my library by clicking on the Add to library… menu option.
TIP - I also ensured that all my CD's that I do add has full ID3 tags and album art
To fetch the media library from WMP, we have to use a little bit of COM
“Microsoft COM (Component Object Model) technology in the Microsoft Windows-family of Operating Systems enables software components to communicate. COM is used by developers to create re-usable software components, link components together to build applications, and take advantage of Windows services. The family of COM technologies includes COM+, Distributed COM (DCOM) and ActiveX® Controls.”
Adding a reference to a COM component is just as easy as adding a reference to a .NET assembly. Click the Project menu and select Add Reference, then click the COM tab on the Add Reference dialog.
The WMP library is a flat structure of media items, so the Albums -> Tracks hierarchy must be created manually. Here is our Model
We will be abstracting the fetching of the data by using a IMediaLibraryRepository. By using a interface we have the added advantage of supporting other media sources (like iTunes, etc) in the future
C#:
public interface IMediaLibraryRepository { IList<Album> GetAlbums(); }
And here is our WMP-specific implementation
C#:
public class WMPMediaLibraryRepository : IMediaLibraryRepository { public IList<Album> GetAlbums() { List<Album> Albums = new List(); WindowsMediaPlayer wmp = new WindowsMediaPlayer(); IWMPPlaylist playlist = wmp.mediaCollection.getAll(); for (int i = 0; i < playlist.count; i++) { IWMPMedia media = (IWMPMedia)playlist.get_Item(i); Track track = new Track(); track.Title = media.getItemInfo("Title"); track.Location = media.getItemInfo("SourceUrl"); track.Number = media.getItemInfo("OriginalIndex"); string albumName = media.getItemInfo("Album"); var album = (from a in Albums where a.Name == albumName select a).FirstOrDefault(); if (album != null) { album.Tracks.Add(track); } else { Album a = new Album(); a.Name = albumName; string dir = System.IO.Path.GetDirectoryName(track.Location); FileInfo file = new FileInfo(System.IO.Path.Combine(dir, "Folder.jpg")); if (file.Exists) { a.Cover = file.FullName; } a.Artist = media.getItemInfo("AlbumArtist"); a.Tracks.Add(track); if (albumName != string.Empty) { Albums.Add(a); } } } return Albums; } }
All the interaction between the View and the ViewModel happens by using ICommand. We will be using the RelayCommand
RelayCommand - An ICommand whose delegates can be attached for Execute and CanExecute
The MediaViewModel exposes the following commands
To create a RelayCommand, we first need the CanExecute and Execute delegates
C#:
private bool SongUpCanExecute(object parameter) { return (TracksCollectionView.CurrentPosition > 0); } private void SongUpExecute(object parameter) { if (TracksCollectionView != null) { TracksCollectionView.MoveCurrentToPrevious(); } }
And then create the command
C#:
private ICommand songUp; public ICommand SongUp { get { if (songUp == null) { songUp = new RelayCommand(SongUpExecute, SongUpCanExecute); } return songUp; } }
The RelayCommand is very well suited to the M-V-VM pattern because it allows me to encapsulate the whole command and its executing logic very cleanly in my ViewModel. The View can then just bind to these commands!
For more information about custom ICommand implementations, read The Power of ICommand
“The Great Library of Alexandria was founded in 300 B.C.E. with the grand objective of collecting the world's knowledge in one place; at its height, the library contained nearly 750,000 scrolls. In the modern world, the British Library contains one of the foremost collections; among its twenty million books and manuscripts are some of the rarest works in existence. It holds the Diamond Sutra, the oldest printed book; Mercator's first atlas of Europe; the Lindisfarne Gospels; Leonardo da Vinci's personal notebook; the Magna Carta; and the Codex Sinaiticus, one of the two earliest Christian Bibles. Such unique items must, of course, be treated with the utmost care. If they are on public display at all, they are well protected behind glass, and direct interaction is limited to a handful of individuals.
Happily, these works are now being digitized for the first time in order to reach a broad audience. Even better, the digitized versions are being turned into a rich interactive experience that adds curatorial content and brings the books to life. In collaboration with a UK-based software developer, the British Library developed a Windows®-based application called Turning the Pages that offers a virtual facsimile in three-dimensional space of a growing number of the library's most precious items”
Turning the Pages with WPF by Tim Sneath
By using the free book control (released by Mitsuru Furuta on CodePlex), we will be transforming our WMP media library into a book browsing experience!
To use the controls, we need to reference the WPMMitsuControls.dll and add the following namespace
xmlns:controls="clr-namespace:WPFMitsuControls;assembly=WPFMitsuControls"
Because Book derive from ItemsControl, we can bind it to any collection using ItemsSource and change the ItemTemplate (Like we would using ListBox, ListView, etc)
<controls:Book ItemsSource="..."> <controls:Book.ItemTemplate> ... </controls:Book.ItemTemplate> </controls:Book>
We will be using the status register (Base + 1) for feedback from the keypad. To access the keypad we need a hardware IO driver (I will be using inpout32.dll). inpout32.dll is a win32 dll so we need to p/invoke
C#:
public class PortAccess { [DllImport("inpout32.dll", EntryPoint = "Out32")] public static extern void Output(int adress, int value); [DllImport("inpout32.dll", EntryPoint = "Inp32")] public static extern int Input(int adress); }
For more information on how to access the LPT port using managed code, first read the following CodeProject article:
This is a very basic schematic of how my keypad is wired up...
I had a keypad laying round which I used but you can also use normal push buttons available at your local electronics shop (Here is a list of push buttons available from RadioShack)
The last part we need to cover is how to react to a key being pressed on the keypad. I sub-classed the WPF Window and created my own WindowWithKeypadSupport. WindowWithKeypadSupport has a background thread running which monitors the LPT port. If a button is pressed, it raises a PreviewKeypadDown routed event.
C#:
public class WindowWithKeypadSupport : Window { public static readonly RoutedEvent PreviewKeypadDownEvent; static WindowWithKeypadSupport() { WindowWithKeypadSupport.PreviewKeypadDownEvent = EventManager.RegisterRoutedEvent( "PreviewKeypadDown", RoutingStrategy.Bubble, typeof(KeypadEventHandler), typeof(WindowWithKeypadSupport)); } public event RoutedEventHandler PreviewKeypadDown { add { base.AddHandler(WindowWithKeypadSupport.PreviewKeypadDownEvent, value); } remove { base.RemoveHandler(WindowWithKeypadSupport.PreviewKeypadDownEvent, value); } } // The rest of the class is omited for brevity }
To raise the event, we need to invoke back to the UI thread
C#:
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate
{
KeypadEventArgs e = new KeypadEventArgs(
WindowWithKeypadSupport.PreviewKeypadDownEvent, this);
e.Key = CreateKeyFromIOPortValue(keyValue);
base.RaiseEvent(e);
}, null);
Here is a example of how to instantiate the WindowWithKeyadSupport
<controls:WindowWithKeypadSupport x:Class="ClassicJukebox.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:ClassicJukebox" PreviewKeypadDown="WindowWithKeypadSupport_PreviewKeypadDown" />
TIP - I also react to keyboard buttons being pressed... Use the left, right, up, down and enter keys to control the jukebox
And thats it...
WPF provides a very powerful infrastructure for creating applications that can mix 3D & hardware effortless! The binding architecture and command support allows for great separation of concerns!
And probably the most important advantage of WPF? It makes writing applications fun…
Rudi Grobler's main area of interest is development in the embedded space (his day-to-day job). In the last 10 years Rudi interfaced to various devices in the embedded space ranging from Graphic LCDs using parallel port, various bill acceptors, RoboHum, smart card readers, Wii remote, data acquisition devices, petrol pumps and much, much more!About 2 years ago, he received a copy of Charles Petzold's WPF book and fell in love…
His ramblings can be found at http://dotnet.org.za/rudi
Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation,
please create a new thread in our Forums,
or
Contact Us and let us know.
Follow the Discussion
Oops, something didn't work.
What does this mean?
Following an item on Channel 9 allows you to watch for new content and comments that you are interested in. You need to be signed in to Channel 9 to use this feature.What does this mean?
Following an item on Channel 9 allows you to watch for new content and comments that you are interested in and view them all on your notifications page.sign up for email notifications?
i am making an UI in Visual Studio 2008(C#).
i want my media player to pause when i click on some PAUSE button and then resume when i click on PLAY button. i specifically dont want to use the buttons of WMP.
can i get a code for the above specified problem
thanks
reply at: kautuk.kamal@gmail.com
@kautuk super easy with WPF mediaelement. MSDN article even has a reference app you can view and manipulate. http://msdn.microsoft.com/en-us/library/system.windows.controls.mediaelement.aspx
Remove this comment
Remove this thread
close