{"id":1013,"date":"2009-11-06T14:17:00","date_gmt":"2009-11-06T14:17:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2009\/11\/06\/linking-zune-media-items-with-linq-part-1-matt-gertz\/"},"modified":"2024-07-05T12:42:31","modified_gmt":"2024-07-05T19:42:31","slug":"linking-zune-media-items-with-linq-part-1-matt-gertz","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/linking-zune-media-items-with-linq-part-1-matt-gertz\/","title":{"rendered":"Linking Zune media items with LinQ, Part 1 (Matt Gertz)"},"content":{"rendered":"<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">Way back in October 2007, I wrote up a few posts (<\/font><a href=\"http:\/\/blogs.msdn.com\/vbteam\/archive\/2007\/10\/30\/let-the-music-play-matt-gertz.aspx\"><font color=\"#0000ff\" size=\"3\" face=\"Calibri\">here<\/font><\/a><font size=\"3\" face=\"Calibri\"> and <\/font><a href=\"http:\/\/blogs.msdn.com\/vbteam\/archive\/2007\/11\/13\/one-is-the-loneliest-number-matt-gertz.aspx\"><font color=\"#0000ff\" size=\"3\" face=\"Calibri\">here<\/font><\/a><font size=\"3\" face=\"Calibri\">) on my experiments with the Windows Media Player object model.<span>&nbsp; <\/span>The problem I was trying to solve was that, when I had a playlist set to &ldquo;shuffle,&rdquo; WMP would break up songs that should always play together (for example, Jackson Browne&rsquo;s &ldquo;The Load-Out&rdquo; and &ldquo;Stay&rdquo;, or Pink Floyd&rsquo;s &ldquo;Brain Damage&rdquo; and &ldquo;Total Eclipse&rdquo;).<span>&nbsp; <\/span>In those posts, I worked around this by building my own shuffler which would emit a new randomized playlist which preserved those links, and then playing that playlist.<span>&nbsp; <\/span>A few months later, after I bought my Zune 80, <\/font><a href=\"http:\/\/blogs.msdn.com\/vbteam\/archive\/2008\/09\/19\/building-a-zune-playlist-matt-gertz.aspx\"><font size=\"3\" face=\"Calibri\">I updated the program<\/font><\/a><font size=\"3\" face=\"Calibri\"> to copy the playlist to a ZPL format, since the format was essentially identical to WPL.<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">Although this was a good investigation into the WMP object model, I&rsquo;ve never been happy with the program.<span>&nbsp; <\/span>First of all, for the program to work, I had to add metadata to the actual music tracks, and anything could come along and blow that metadata away.<span>&nbsp; <\/span>Second, the tracks had to already be adjacent in the parent playlist for it to work at all.<span>&nbsp; <\/span>Third, I had to bring up the WMP just to shuffle a playlist, which is pretty heavyweight.<span>&nbsp; <\/span>Finally, since I mostly care about Zune playlists these days and not WMP at all, it seemed the height of hackery to bring up the WMP to generate something for Zune (since the Zune object model is not public). <\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">So, last week, after seeing my metadata blown away again when I carelessly updated my tracks after upgrading to Windows 7, I decided to work on a more permanent solution.<span>&nbsp; <\/span>Why bring up the WMP at all (or Zune, for that matter), when the playlists themselves are just XML, and the track just entries into those?<span>&nbsp; <\/span><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">After some experiments with parsing the XML by following the parent\/child chain, which seemed kludge to me, I came across a <\/font><a href=\"http:\/\/blogs.msdn.com\/xmlteam\/archive\/2006\/12\/18\/converting-simple-itunes-playlists-to-zune-playlists-using-vb-9-0.aspx\"><font color=\"#0000ff\" size=\"3\" face=\"Calibri\">post by Avner<\/font><\/a><font size=\"3\" face=\"Calibri\"> in which he discusses porting iTunes playlists to Zune, leveraging LinQ to help with the data parsing.<span>&nbsp; <\/span>I realized right away that I could do something very similar in this case, and came up with what I think is a pretty elegant solution.<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">So here&rsquo;s the plan:<span>&nbsp; <\/span>the application will:<\/font><\/p>\n<p class=\"MsoListParagraphCxSpFirst\"><span><span><font size=\"3\" face=\"Calibri\">(1)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">Load in a playlist that the user chooses<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font size=\"3\" face=\"Calibri\">(2)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">Allow the user to rearrange the playlist<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font size=\"3\" face=\"Calibri\">(3)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">Allow the user to link certain tracks together (and unlink them)<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font size=\"3\" face=\"Calibri\">(4)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">Shuffle the playlist on command, preserving the linkages<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font size=\"3\" face=\"Calibri\">(5)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">Allow the user to change the title of the playlist<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font size=\"3\" face=\"Calibri\">(6)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">Allow the user to cave the playlist (or a copy of it)<\/font><\/p>\n<p class=\"MsoListParagraphCxSpLast\"><span><span><font size=\"3\" face=\"Calibri\">(7)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">And, most important, persist the linkage data between sessions in such a way that the information won&rsquo;t get blown away.<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">Let&rsquo;s get started!<\/font><\/p>\n<h2><font color=\"#4f81bd\" size=\"4\" face=\"Cambria\">The form<\/font><\/h2>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">Create a Windows Form Application (about 430 x 300) containing the following:<\/font><\/p>\n<p class=\"MsoListParagraphCxSpFirst\"><span><span><font size=\"3\" face=\"Calibri\">(1)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">A ListBox, about 290 x 180 and positioned on the left side, with the SelectionMode property set to &ldquo;MultiExtended&rdquo; and the DrawMode set to &ldquo;OwnerDrawFixed.&rdquo; <\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font size=\"3\" face=\"Calibri\">(2)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">Above that, a Label and EditBox, with the Label text set to &ldquo;&amp;Title&rdquo;.<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font size=\"3\" face=\"Calibri\">(3)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">To the right of those, five Buttons going down the right side, labeled &ldquo;Link&rdquo;, &ldquo;Unlink&rdquo;, &ldquo;Move Up&rdquo;, &ldquo;Move Down&rdquo;, and &ldquo;Shuffle&rdquo;.<\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font size=\"3\" face=\"Calibri\">(4)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">A MenuStrip.<span>&nbsp; <\/span>Select it, and on the right side of the strip, click the tiny right-pointing triangle icon and choose &ldquo;Insert Standard Items&rdquo; from the resulting popup.<span>&nbsp; <\/span>Now, go back and remove all of the items except File (Open, Close, Save, Save As, Exit) and Help (About).<span>&nbsp; <\/span>The Edit and Tools menu can be completely removed; we won&rsquo;t be using those.<\/font><\/p>\n<p class=\"MsoListParagraphCxSpLast\"><span><span><font size=\"3\" face=\"Calibri\">(5)<\/font><span>&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\" face=\"Calibri\">An OpenFileDialog and a SaveFileDialog.<span>&nbsp; <\/span>The Filter property of both should be set to &ldquo;Zune playlists|*.zpl&rdquo; (without the quotes).<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">In my example, I also disabled the Maximize box in the form, added an icon and title to the form and application, etc., but those aren&rsquo;t strictly necessary for the exercise.<\/font><\/p>\n<h2><font color=\"#4f81bd\" size=\"4\" face=\"Cambria\">The Zune playlist<\/font><\/h2>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">The format of a Zune playlist (version 2.0) looks like this (memorize this, it will be useful later):<\/font><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;smil&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;head&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;guid&gt; <i>(some guid)<\/i>&lt;\/guid&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\"><span>&nbsp;&nbsp;&nbsp; <\/span>&lt;meta name=&#8221;creatorId&#8221; content=&#8221;<i>(some guid)<\/i>&#8220;<span>&nbsp; <\/span>\/&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\"><span>&nbsp;<\/span><span>&nbsp;&nbsp; <\/span>&lt;meta name=&#8221;Subtitle&#8221; \/&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\"><span>&nbsp;&nbsp;&nbsp; <\/span>&lt;meta name=&#8221;ContentPartnerName&#8221; \/&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\"><span>&nbsp;&nbsp;&nbsp; <\/span>&lt;meta name=&#8221;ContentPartnerNameType&#8221; \/&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\"><span>&nbsp;&nbsp;&nbsp; <\/span>&lt;meta name=&#8221;ContentPartnerListID&#8221; \/&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\"><span>&nbsp;&nbsp;&nbsp; <\/span>&lt;meta name=&#8221;ItemCount&#8221; content=&#8221;<i>(number of tracks)<\/i>&#8221; \/&gt; <\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\"><span>&nbsp;&nbsp;&nbsp; <\/span>&lt;meta name=&#8221;TotalDuration&#8221; content=&#8221; <i>(total duration)<\/i> &#8221; \/&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\"><span>&nbsp;&nbsp;&nbsp; <\/span>&lt;meta name=&#8221;AverageRating&#8221; content=&#8221;<i>(whatever the average rating is)<\/i>&#8221; \/&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\"><span>&nbsp;&nbsp;&nbsp; <\/span>&lt;meta name=&#8221;Generator&#8221; content=&#8221;Zune &#8212; 4.0.740.0&#8243; \/&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;title&gt; <i>(some title)<\/i> &lt;\/title&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;\/head&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;body&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;seq&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;media src=&#8221;<i>(file path of the track on disk)<\/i>&#8221; serviceId=&#8221;{BF0A0E00-0100-11DB-89CA-0019B92A3933}&#8221; albumTitle=&#8221;<i>(album title)<\/i>&#8221; albumArtist=&#8221;<i>(artist)<\/i>&#8221; trackTitle=&#8221;<i>(name of the track)<\/i>&#8221; trackArtist=&#8221;<i>(track artist)<\/i>&#8221; duration=&#8221;<i>(track duration)<\/i>&#8221; \/&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;media &hellip; \/&gt; <i>(etc&hellip; one for each track)<\/i><\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;\/seq&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;\/body&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><font face=\"Calibri\">&lt;\/smil&gt;<\/p>\n<p><\/font><\/span><\/p>\n<h2><font color=\"#4f81bd\" size=\"4\" face=\"Cambria\">Code for the controls<\/font><\/h2>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">The rest of this post will be organized based on the controls, starting from the top.<\/font><\/p>\n<h3><font color=\"#4f81bd\" size=\"3\" face=\"Cambria\">The Form<\/font><\/h3>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">The only code associated with the form itself is the event handler for Load, a few member variables, and a helper class.<span>&nbsp; <\/span>Let&rsquo;s take those in reverse order:<\/font><\/p>\n<h4><em><font color=\"#4f81bd\" face=\"Cambria\">The helper class, xmlMediaEntry<\/font><\/em><\/h4>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">We&rsquo;ll be reading the Zune playlist using the XDocument class, and then we&rsquo;ll be using LinQ to retrieve individual &lt;media&gt;&hellip;&lt;\/media&gt; tag pairs representing each track.<span>&nbsp; <\/span>These will be handed to us as XElements, and as we will want to add each of the tracks to the listbox, we&rsquo;ll want to wrap these in an object that will expose the proper information to the ListBox &ndash; namely, a human-readable string.<span>&nbsp; <\/span>We will also want to have a way to link a track to another track, and we&rsquo;ll be using a doubly-linked list to do this.<span>&nbsp; <\/span>So:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Class<\/span> xmlMediaEntry<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> xmlElem <span>As<\/span> XElement <span><\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> PrevLinkedElement <span>As<\/span> xmlMediaEntry = <span>Nothing<\/span> <span><\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> NextLinkedElement <span>As<\/span> xmlMediaEntry = <span>Nothing<\/span> <span><\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">That code allows us to cache the XElement and also point to other elements of this class backwards and forward.<span>&nbsp; <\/span>The header node for a chain of linked songs will have PrevLinkedElement remaining as Nothing; the tail node will have NextLinkedElement remain as Nothing; songs in the middle of the chain will have both of those set to some other node.<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">The following constructor allows us to initialize the object with the XElement to be cached.<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Sub<\/span> <span>New<\/span>(<span>ByVal<\/span> xelem <span>As<\/span> XElement)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>xmlElem = xelem<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Sub<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">This code, exposed publically as a shared method, allows us to create a canonical (and readable) way to refer to a track in an XElement.<span>&nbsp; <\/span>To use one of my previous examples, the resulting value might be &ldquo;The Load-Out (Jackson Browne)&rdquo;:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> <span>Shared<\/span> <span>Function<\/span> CreateMediaString(<span>ByVal<\/span> elem <span>As<\/span> XElement) <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Return<\/span> elem.Attribute(<span>&#8220;trackTitle&#8221;<\/span>).Value &amp; _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>&#8221; (&#8220;<\/span><span> &amp; elem.Attribute(<span>&#8220;trackArtist&#8221;<\/span>).Value &amp; <span>&#8220;)&#8221;<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Function<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">I can then leverage that function to override the ToString for the xmlMediaEntry:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> <span>Overrides<\/span> <span>Function<\/span> ToString() <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Return<\/span> CreateMediaString(xmlElem)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Function<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Class<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">And that&rsquo;s all I need in that class.<span>&nbsp; <\/span>Once I add an instance of it to the ListBox, it will show up with nice readable text, and I&rsquo;ll be able to navigate between it and any other linked songs (if any).<\/font><\/p>\n<h4><em><font color=\"#4f81bd\" face=\"Cambria\">Member Variables<\/font><\/em><\/h4>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">I&rsquo;ll need a few variables to keep track of the state of the file, and these should all be\nself-explanatory:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> FileLoaded <span>As<\/span> <span>Boolean<\/span> = <span>False<\/span> <span>&#8216; Do we have a file loaded into the listbox?<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> FileChanged <span>As<\/span> <span>Boolean<\/span> = <span>False<\/span> <span>&#8216; Has the playlist changed since it was last loaded\/saved?<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> FilePath <span>As<\/span> <span>String<\/span> <span>&#8216; Where was the file last loaded from\/saved to?<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> FileDirectory <span>As<\/span> <span>String<\/span> <span>&#8216; What directory was the file last loaded from\/saved to?<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">We&rsquo;ll also need to keep track of some of the playlist&rsquo;s metadata.<span>&nbsp; <\/span>Each playlist has a GUID associated with it (if you don&rsquo;t know what a GUID is, don&rsquo;t worry about it &ndash; think of it as a unique identifier); if we do a &ldquo;Save As&rdquo; to a different file, we&rsquo;ll want a different GUID.<span>&nbsp; <\/span>The user might also change the title of the playlist, and we should cache our creatorId format since it might be unique to the user&rsquo;s situation:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> playlistGuid <span>As<\/span> <span>String<\/span> <span>&#8216; What is the GUID of this playlist?<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> playlistTitle <span>As<\/span> <span>String<\/span> <span>&#8216; What is the title of this playlist?<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> playlistCreatorId <span>As<\/span> XElement <span>&#8216; What is the creator information of this playlist?<\/p>\n<p><\/span><\/span><\/p>\n<h4><em><font color=\"#4f81bd\" face=\"Cambria\">Events<\/font><\/em><\/h4>\n<p class=\"MsoNormal\"><font size=\"3\" face=\"Calibri\">The Form only has two events to handle that we care about &ndash; the Load event, and the FormClosing event.<span>&nbsp; <\/span>For the Load event, we&rsquo;ll want to make sure that our menu items and buttons are enabled appropriately, and that we appropriately generate random numbers later on:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> <span>Sub<\/span> VBShuffleForm_Load(<span>ByVal<\/span> sender <span>As<\/span> System.Object, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>ByVal<\/span><span> e <span>As<\/span> System.EventArgs) <span>Handles<\/span> <span>MyBase<\/span>.Load<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Microsoft.VisualBasic.Randomize()<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><s><\/s><\/span><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Way back in October 2007, I wrote up a few posts (here and here) on my experiments with the Windows Media Player object model.&nbsp; The problem I was trying to solve was that, when I had a playlist set to &ldquo;shuffle,&rdquo; WMP would break up songs that should always play together (for example, Jackson Browne&rsquo;s [&hellip;]<\/p>\n","protected":false},"author":258,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[22,195],"tags":[94,101,166,185],"class_list":["post-1013","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-matt-gertz","category-visual-basic","tag-linqvb9","tag-matt-gertz","tag-vb2008","tag-xml"],"acf":[],"blog_post_summary":"<p>Way back in October 2007, I wrote up a few posts (here and here) on my experiments with the Windows Media Player object model.&nbsp; The problem I was trying to solve was that, when I had a playlist set to &ldquo;shuffle,&rdquo; WMP would break up songs that should always play together (for example, Jackson Browne&rsquo;s [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/1013","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/258"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=1013"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/1013\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=1013"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=1013"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=1013"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}