The Media Center Sandbox

Resources and discussion for developing experiences in the Windows Media Center platform.
Welcome to The Media Center Sandbox Sign in | Join | Help
in Search

MCML - The Basic Apps - A Real One - VMCMusicArtistLister

Last post 05-21-2007, 3:28 PM by IgnoranceIsBliss. 15 replies.
Page 1 of 2 (16 items)   1 2 Next >
Sort Posts: Previous Next
  •  04-25-2007, 6:34 AM 3031

    MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    At last, I've achieved a sort of landmark. After (what) three, four weeks of almost solid work and experimentation, of tears, and anger, of delight and joy, of setback and advance, I've done it. I've created a real application with an installer :)

    VMCMusicArtistLister is a Vista Media Center (VMC) foreground addin application that allows you to display in a list every music artist in your [WMP] library. (I will add some code to enable you to scroll trhough the list more easily asap).

    You can press OK on the remote for any artist and get a list of all the songs for that artist. You can then use the right arrow button and select a song. If you press OK it will give you two option:

    1) Play the currently selected song.

    2) Add all the listed songs to a playlist that will be labelled VMC-Artistname. The entry is also recorded in a wpl file in your Usename|Music|Playlists folder. Please remember that to remove a playlist you should do it from the library of WMP. if you simply delete the file, the entries remain in the Library.

    If you repeat the operation for the same artist the original playlist will be replaced.

    You can download the app installer from www.gfmapps.co.uk

    Here's the class: (VMCMusicArtistListerClasses)
    ----------------
    using System;
    using System.IO;
    using System.Drawing.Imaging;
    using System.Diagnostics;
    using Microsoft.MediaCenter;
    using Microsoft.MediaCenter.UI;
    using Microsoft.MediaCenter.Hosting;
    using WMPLib;

    namespace gfmApps.VMC
    {
        public class ArtistList : ModelItem
        {

            private Choice artistschoice;
            private Choice songschoice;

            private ArrayListDataSet Artists;
            private ArrayListDataSet Songs;

            private WindowsMediaPlayer Mplayer;
            public static IWMPMediaCollection MplayerCollection;

            private IWMPMediaCollection2 Library;
            private IWMPStringCollection2 ListArtist;
            private IWMPPlaylist ListSongs;
            private IWMPPlaylist pList;

            public ArtistList()
            {
                Mplayer = new WindowsMediaPlayer();
                Library = (WMPLib.IWMPMediaCollection2)Mplayer.mediaCollection;
                ListArtist = (WMPLib.IWMPStringCollection2)Library.getAttributeStringCollection("Artist", "Audio");
                MplayerCollection = Mplayer.mediaCollection;

                Artists = new ArrayListDataSet();

                for (int i = 0; i < ListArtist.count; i++) 
                {
                    if (ListArtist.Item(i) != "") Artists.Add(ListArtist.Item(i).ToString());
                }
                artistschoice = new Choice();
                artistschoice.Options = Artists;
        
                Songs = new ArrayListDataSet();
                Songs.Add("Tracks"); //just need this for the initial display
                songschoice = new Choice();
                songschoice.Options = Songs;

            }

            public Choice ArtistsChoice
            {
                get { return artistschoice; }
            }

            public Choice SongsChoice
            {
                set
                {
                    songschoice = value;
                    FirePropertyChanged("SongsChoice");
                }
                get { return songschoice; }
            }

            public string mySelectedArtist;//save having to pass it into the OnButtnClick
            public string mySelectedTrack;

            public void Clicked1(String SelectedArtist)
            {
                mySelectedArtist = SelectedArtist;
                Songs.Clear();

                ListSongs = Mplayer.mediaCollection.getByAuthor(SelectedArtist);

                for (int i = 0; i < ListSongs.count; i++) 
                {
                    Songs.Add(ListSongs.get_Item(i).name);
                }

                songschoice.Options = Songs;
                SongsChoice = songschoice;
           }

           
            public void Clicked2(String SelectedTrack)
            {
                mySelectedTrack = SelectedTrack;

                object[] buttons = new object[] { "Play It", "Playlist All" };
                string imagePath = Path.GetTempPath() + Guid.NewGuid().ToString("N") + ".png";
                Resources.BlankSmall.Save(imagePath, ImageFormat.Png); //create a temporary copy of the image in the temp folder from the resources
                AddInHost.Current.MediaCenterEnvironment.DialogNotification("VMC", buttons, 5, imagePath, new DialogClosedCallback(OnButtnClick));
                //AddInHost.Current.MediaCenterEnvironment.DialogNotification("VMC", buttons, 5, "file://C:\\Users\\Gordon\\Documents\\Visual Studio 2005\\Projects\\VMCMusicArtistLister\\VMCMusicArtistLister\\Images\\BlankSmall.png", new DialogClosedCallback(OnButtnClick));
                File.Delete(imagePath);
               
            }

            public void OnButtnClick(Microsoft.MediaCenter.DialogResult buttn)
            {
                if (buttn.ToString() == "100")
                {
                    IWMPPlaylist ListSongs = MplayerCollection.getByName(mySelectedTrack); 
                    IWMPMedia Track = ListSongs.get_Item(0);    
                    Microsoft.MediaCenter.Hosting.AddInHost.Current.MediaCenterEnvironment.PlayMedia(MediaType.Audio, Track.sourceURL, false);
                }
                if (buttn.ToString() == "101")
                {
                    //if empty create a new playlist file so we can access it
                    if (Mplayer.playlistCollection.getByName("VMCMAL - " + mySelectedArtist).count == 0)
                        Mplayer.playlistCollection.newPlaylist("VMCMAL - " + mySelectedArtist);

                   
                    // Retrieve the playlist and clear it
                    pList = Mplayer.playlistCollection.getByName("VMCMAL - " + mySelectedArtist).Item(0);
                    pList.clear();

                    //Add the items
                    for (int i = 0; i < ListSongs.count; i++)
                    {
                        pList.appendItem(ListSongs.get_Item(i));
                    }

                }
                if (buttn == DialogResult.Cancel)
                {
                    //dbug("Cancel");
                }
            }

            public void dbug(string str) //just for displaying any variables etc in debugging.
            {
                 AddInHost.Current.MediaCenterEnvironment.Dialog(str, "", DialogButtons.Ok, 0, true);
           }
        }
    }




    Here's the mcml
    ----------------
    <Mcml xmlns="http://schemas.microsoft.com/2006/mcml"
          xmlns:a="assembly://VMCMusicArtistLister,Version=1.0.0.0,Culture=neutral,PublicKeyToken=771db207fea5dc69/gfmApps.VMC"
          xmlns:cor="assembly://MsCorLib/System"
          xmlns:me="Me">

     
      <UI Name="VMCMusicArtistLister">

        <Locals>
          <a:ArtistList Name="TheArtistList" />
         
          <ScrollingHandler Name="ScrollingHandler" HandlerStage="Bubbled"/>
          <ScrollingData Name="ScrollingData" />
        </Locals>

        <Rules>
          <!--
          <Default Target="[Input.KeyInteractive]" Value="true" />
          -->
          <Changed Source="[TheArtistList.SongsChoice.Options]">
            <Actions>
              <PlaySound Sound="resx://VMCMusicArtistLister/gfmApps.VMC.Resources/Noise" />
            </Actions>
          </Changed>
        </Rules>

        <Content>
          <Panel Layout="Form">
            <Children>
              <Text Name ="test" Content="VMCMusicArtistLister" Color="Yellow" >
                <LayoutInput>
                  <FormLayoutInput Left="Parent,.05" Top="Parent,.03" />
                </LayoutInput>
              </Text>

              <me:SimpleScroller1 Name="ScrollArtists" MySource="[TheArtistList]" MyChoice="[TheArtistList.ArtistsChoice]" >
                <LayoutInput>
                  <FormLayoutInput Left="Parent,.05" Top="Parent,.10" />
                </LayoutInput>
              </me:SimpleScroller1>

              <me:SimpleScroller2 Name="ScrollSongs" MySource="[TheArtistList]" MyChoice="[TheArtistList.SongsChoice]">
                <LayoutInput>
                  <FormLayoutInput Left="Parent,.55" Top="Parent,.10" />
                </LayoutInput>
              </me:SimpleScroller2>

            </Children>
          </Panel>
        </Content>

      </UI>

      <UI Name="SimpleScroller1">
        <Properties>
          <a:ArtistList Name="MySource" a:ArtistList="$Required" />
          <Choice Name="MyChoice" Choice="$Required" />
        </Properties>

        <Locals>
          <ScrollingHandler Name="ScrollingHandler" />
          <ScrollingData Name="ScrollingData" />
         
          <MouseWheelHandler Name="WheelHandler"/>
        </Locals>

        <Rules>
          <!--
          <Default Target="[Input.KeyInteractive]" Value="true" />
          -->
          <Default Target="[ScrollingHandler.ScrollingData]" Value="[ScrollingData]"/>
          <Default Target="[ScrollingData.Repeater]" Value="[SimpleRepeater]"/>

          <!--
          <Changed Source="[WheelHandler.DownInvoked]" >
            <Actions>
              <Set Target="[test.Content]" Value="Down" />
            </Actions>
          </Changed>
          <Changed Source="[WheelHandler.UpInvoked]" >
            <Actions>
              <Set Target="[test.Content]" Value="Up" />
            </Actions>
          </Changed>
          -->
        </Rules>

        <Content>
          <Scroller Name="MyScroller" Orientation="Vertical" FadeSize="10" MaximumSize="0,550" ScrollingData="[ScrollingData]">
            <Children>
              <Repeater Name="SimpleRepeater" Source="[MyChoice.Options]">
                <Layout>
                  <FlowLayout Orientation="Vertical" Spacing="2,0"/>
                </Layout>

                <Content>
                  <me:ShowItem1 MySource="[MySource]" MyDataItem="[RepeatedItem!cor:String]" />
                </Content>
              </Repeater>
            </Children>
          </Scroller>
        </Content>
      </UI>

      <UI Name="ShowItem1">
        <Properties>
          <a:ArtistList Name="MySource" a:ArtistList="$Required" />
          <cor:String Name="MyDataItem" cor:String="$Required" />
        </Properties>

        <Locals>
          <ClickHandler Name="Clicker"/>
        </Locals>

        <Rules>
          <Default Target="[Input.KeyInteractive]" Value="true" />

          <Condition Source="[Clicker.Clicking]" SourceValue="true" >
            <!--Order Matters!-->
            <Actions>
              <Set Target="[Label.Color]" Value="Blue" />
            </Actions>
          </Condition>
          <Changed Source="[Clicker.Invoked]">
            <Actions>
              <Invoke Target="[MySource.Clicked1]" SelectedArtist="[MyDataItem]" />
            </Actions>
          </Changed>

          <Condition Source="[Input.KeyFocus]" SourceValue="true">
            <Actions>
              <Set Target="[Label.Color]" Value="Firebrick" />
            </Actions>
          </Condition>

        </Rules>

        <Content>
          <Text Name="Label" Content="[MyDataItem]" Color="White"/>
        </Content>
      </UI>

      <UI Name="SimpleScroller2">
        <Properties>
          <a:ArtistList Name="MySource" a:ArtistList="$Required" />
          <Choice Name="MyChoice" Choice="$Required" />
        </Properties>

        <Locals>
          <ScrollingHandler Name="ScrollingHandler" />
          <ScrollingData Name="ScrollingData" />
        </Locals>

        <Rules>
          <!--
          <Default Target="[Input.KeyInteractive]" Value="true" />
          -->
          <Default Target="[ScrollingHandler.ScrollingData]" Value="[ScrollingData]"/>
          <Default Target="[ScrollingData.Repeater]" Value="[SimpleRepeater]"/>
        </Rules>

        <Content>
          <Scroller Name="MyScroller" Orientation="Vertical" FadeSize="10" MaximumSize="0,550" ScrollingData="[ScrollingData]">
            <Children>
              <Repeater Name="SimpleRepeater" Source="[MyChoice.Options]">
                <Layout>
                  <FlowLayout Orientation="Vertical" Spacing="2,0"/>
                </Layout>

                <Content>
                  <me:ShowItem2 MySource="[MySource]" MyDataItem="[RepeatedItem!cor:String]" />
                </Content>
              </Repeater>
            </Children>
          </Scroller>
        </Content>
      </UI>

      <UI Name="ShowItem2">
        <Properties>
          <a:ArtistList Name="MySource" a:ArtistList="$Required" />
          <cor:String Name="MyDataItem" cor:String="$Required" />
        </Properties>

        <Locals>
          <ClickHandler Name="Clicker"/>
        </Locals>

        <Rules>
          <Default Target="[Input.KeyInteractive]" Value="true" />

          <Condition Source="[Clicker.Clicking]" SourceValue="true" >
            <!--Order Matters!-->
            <Actions>
              <Set Target="[Label.Color]" Value="Blue" />
            </Actions>
          </Condition>
          <Changed Source="[Clicker.Invoked]">
            <Actions>
              <Invoke Target="[MySource.Clicked2]" SelectedTrack="[MyDataItem]" />
            </Actions>
          </Changed>

          <Condition Source="[Input.KeyFocus]" SourceValue="true">
            <Actions>
              <Set Target="[Label.Color]" Value="Firebrick" />
            </Actions>
          </Condition>

        </Rules>

        <Content>
          <Text Name="Label" Content="[MyDataItem]" Color="White"/>
        </Content>
      </UI>

    </Mcml>


    If you see anything that can be improved, or tidied up or whatever, please let me know - I'm happy to learn better practice. :)

    Oh - If you use any of the code in your app and yours makes you a millionaire, please remember me! :()


    Gordon: Has reached the end!
  •  04-25-2007, 9:29 AM 3033 in reply to 3031

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    Uhmm just noticed that I seem to be having some problems with the navigation using the remote control. I thought I'd solved this on my test machine, but on one machine I have the left navigation key doesn't work!? - That's wierd. On another machine it seems to go back up the list before shifting to the left artist list.

    And it is so slow to scroll down a list?

    Okay back to the sdk and the samples, and Igs blog which I just noted had posted the scroller - where were you when I needed you! :)


    Gordon: Has reached the end!
  •  04-25-2007, 12:59 PM 3041 in reply to 3033

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    Found this statement in the sdk under Navigation:

    • Multiple scrolling sections (even if they are in sync with each other) typically do not test well.

    Please don't, don't tell me that what I'm doing is once again ****'d

    Can you actually do anything useful with this stuff! which doesn't require massive amounts of work to work round it's inadequacies. I'm getting sick of this!






    Gordon: Has reached the end!
  •  04-25-2007, 3:32 PM 3046 in reply to 3041

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    Hehe - well done.

    ....but I've got to ask, have you considered working on anything a little more practical?

    You could have done this quite easily as a 'More With This' addin, saving you a buttload of time having to write an interface that allows you to search for artists. Why re-invent the wheel? Or was it just for practise?

    And do remember that Windows Media Player allows you to create playlists based on searches. If you create search-playlists like these, it will ensure that any new tracks you add from a particular artist will still be included in the list.

    Hmm...I suppose the next step is to allow you to delete the playlists as well. Your app does need this ability, since if you let something be added from Media Center, you really should be able to delete it. It should be relatively easy to do now - simply a Repeater with all of the playlists.

    Yeah - I've had to override some of the default navigation behaviour in one of my apps. I just added a TypingHandler to the object and caught the 'left' and 'right' buttons - but there are better ways of doing this.

    But nice going - you've got a UI now and are starting to do some real MC development.

    And don't worry - it gets easier as you discover what the limitations are.


    100 downloads a day for Yougle Vista - goin' allright!

    Check out http://www.thedigitallifestyle.com/cs/Blogs/developer/default.aspx and http://www.push-a-button.com.au/products/mce
  •  04-26-2007, 12:12 AM 3055 in reply to 3046

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    I, I don't understand what you mean by A More With This addin??? I was just doing it for practice and it involves lots of basic techniques that I suspect many apps will require.

    Couple of quick questions if you're awake.

    1) Should I perhaps restructure the app to avoid the two scrollers on one ui? Or can you create a navigation between the two and I'm just misreading the sdk. I'm not quite sure what the proper way to use the input handler is.

    2) Can a new page be transparent and overlaid on the one underneath? So My first page has my scroller, the second page has a scroller and it just overlays the first page - am I thinking about this straight? Then my navigation is just using the back key.

    3) I noted some duplication of code in my app namely:

    UI
        scroller1
             showitem1
       scroller2
             showitem2

    Can I pass the showitem as an argument (property) to the scroller, so my scoller can send the output to shpowitem1 or showitem2 as required. (Is this called a delegate in C#)

    4) In your blogs can you look at source and target, as I'm finding these concepts a little harder when applied to UIs for instance I tried to allow the mouse wheel, but couldn't figure out what the target should be.

    Cheers



    Gordon: Has reached the end!
  •  04-27-2007, 11:13 AM 3078 in reply to 3055

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    See http://msdn2.microsoft.com/en-us/library/bb189215.aspx for details on how 'More With This' works.
    Charlie Owen (Microsoft)
  •  04-28-2007, 9:54 AM 3090 in reply to 3078

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    Uhmm, still not quite sure why you are recomending this (More with)?, but hey ho.

    I've had to restructure my app, since the use of the remote to sort our focus was really flaky. I'm assuming that the comment I found in the sdk is related to this since no one commented on it?

    What happens now is that when you select an artist it goes to a new mcml page to display the songs. You can then use the back button as per usual.

    This involved the use of the session.GoToPage(page, properties) method. Charlie showed this in thread : http://discuss.mediacentersandbox.com/forums/thread/3048.aspx

    Here is the main c#
    VMCMusicArtistLister.cs
    ---------------------------
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using Microsoft.MediaCenter.Hosting;
    using Microsoft.MediaCenter.UI;

    using WMPLib;

    namespace gfmApps.VMC
    {
        public class VMCMusicArtistLister : IAddInModule, IAddInEntryPoint
        {
            public void Initialize(Dictionary<string, object> appInfo, Dictionary<string, object> entryPointInfo)
            {
            }

            public void Uninitialize()
            {
            }

            private static HistoryOrientedPageSession s_session;

            public void Launch(AddInHost host)
            {
                host.MediaCenterEnvironment.BackgroundColor = System.Drawing.Color.FromArgb(21, 35, 39);

                s_session = new HistoryOrientedPageSession();
                    s_session.GoToPage("resx://VMCMusicArtistLister/gfmApps.VMC.Resources/VMCMusicArtistLister");
            }
          
            //not sure how best to pass the session object to my other class?
            public static HistoryOrientedPageSession S_Session
            {
                get { return s_session; }
            }
        }
    }

    VLMMusicArtistListerClasses.cs
    ----------------------------------
    using System;
    using System.IO;
    using System.Drawing.Imaging;
    using System.Diagnostics;
    using System.Collections;
    using System.Collections.Generic;
    using Microsoft.MediaCenter;
    using Microsoft.MediaCenter.UI;
    using Microsoft.MediaCenter.Hosting;
    using WMPLib;

    namespace gfmApps.VMC
    {

        public class ArtistList : ModelItem
        {
            private Choice artistschoice;
            private Choice songschoice;

            private ArrayListDataSet Artists;
            private ArrayListDataSet Songs;

            private WindowsMediaPlayer Mplayer;
            public static IWMPMediaCollection MplayerCollection;

            private IWMPMediaCollection2 Library;
            private IWMPStringCollection2 ListArtist;
            private IWMPPlaylist ListSongs;
            private IWMPPlaylist pList;

            public ArtistList()
            {
                Mplayer = new WindowsMediaPlayer();
                Library = (WMPLib.IWMPMediaCollection2)Mplayer.mediaCollection;
                ListArtist = (WMPLib.IWMPStringCollection2)Library.getAttributeStringCollection("Artist", "Audio");
                MplayerCollection = Mplayer.mediaCollection;

                Artists = new ArrayListDataSet();

                for (int i = 0; i < ListArtist.count; i++) 
                {
                    if (ListArtist.Item(i) != "") Artists.Add(ListArtist.Item(i).ToString());
                }
                artistschoice = new Choice();
                artistschoice.Options = Artists;
        
                Songs = new ArrayListDataSet();
                Songs.Add("Tracks"); //just need this for the initial display
                songschoice = new Choice();
                songschoice.Options = Songs;

            }

            public Choice ArtistsChoice
            {
                get { return artistschoice; }
            }

            public Choice SongsChoice
            {
                set
                {
                    songschoice = value;
                    FirePropertyChanged("SongsChoice");
                }
                get { return songschoice; }
            }

            public string mySelectedArtist;//make it easier to access
            public string mySelectedTrack;

            public void Clicked1(String SelectedArtist)
            {
           
                mySelectedArtist = SelectedArtist;
                Songs.Clear();

                ListSongs = Mplayer.mediaCollection.getByAuthor(SelectedArtist);

                for (int i = 0; i < ListSongs.count; i++) 
                {
                    Songs.Add(ListSongs.get_Item(i).name);
                }

                songschoice.Options = Songs;
                SongsChoice = songschoice;

                //goto new page, the parameters are pciked up in the properties section so make sure their names line up!
                Dictionary<string, object> properties = new Dictionary<string, object>();
                properties["ArtistList"] = this;
                properties["SelectedArtist"] = SelectedArtist;
                properties["SongsChoice"] = SongsChoice;

                VMCMusicArtistLister.S_Session.GoToPage("resx://VMCMusicArtistLister/gfmApps.VMC.Resources/VMCMusicArtistListerSongs", properties);

           }
           
            public void Clicked2(String SelectedTrack)
            {
                mySelectedTrack = SelectedTrack;

                object[] buttons = new object[] { "Play It", "Playlist All" };
                string imagePath = Path.GetTempPath() + Guid.NewGuid().ToString("N") + ".png";
                Resources.BlankSmall.Save(imagePath, ImageFormat.Png); //create a temporary copy of the image in the temp folder from the resources
                AddInHost.Current.MediaCenterEnvironment.DialogNotification("VMC", buttons, 5, imagePath, new DialogClosedCallback(OnButtnClick));
                new DialogClosedCallback(OnButtnClick));
                File.Delete(imagePath);
               
            }

            public void OnButtnClick(Microsoft.MediaCenter.DialogResult buttn)
            {
                if (buttn.ToString() == "100")
                {
                    IWMPPlaylist ListSongs = MplayerCollection.getByName(mySelectedTrack); 
                    IWMPMedia Track = ListSongs.get_Item(0);    
                    Microsoft.MediaCenter.Hosting.AddInHost.Current.MediaCenterEnvironment.PlayMedia(MediaType.Audio, Track.sourceURL, false);
                }
                if (buttn.ToString() == "101")
                {
                    //if empty create a new playlist file so we can access it
                    if (Mplayer.playlistCollection.getByName("VMCMAL - " + mySelectedArtist).count == 0)
                        Mplayer.playlistCollection.newPlaylist("VMCMAL - " + mySelectedArtist);

                   
                    // Retrieve the playlist and clear it
                    pList = Mplayer.playlistCollection.getByName("VMCMAL - " + mySelectedArtist).Item(0);
                    pList.clear();

                    //Add the items
                    for (int i = 0; i < ListSongs.count; i++)
                    {
                        pList.appendItem(ListSongs.get_Item(i));
                    }

                }
                if (buttn == DialogResult.Cancel)
                {
                    //dbug("Cancel");
                }
            }

            public void dbug(string str) //just for displaying any variables etc in debugging.
            {
                 AddInHost.Current.MediaCenterEnvironment.Dialog(str, "", DialogButtons.Ok, 0, true);
           }
        }
    }


    here are the mcml pages (resourced)
    VMCMusicArtistList.mcml
    ----------------------------
    <Mcml xmlns="http://schemas.microsoft.com/2006/mcml"
          xmlns:a="assembly://VMCMusicArtistLister,Version=1.0.0.0,Culture=neutral,PublicKeyToken=771db207fea5dc69/gfmApps.VMC"
          xmlns:np="resx://VMCMusicArtistLister/gfmApps.VMC.Resources/VMCMusicArtistListerSongs"
          xmlns:cor="assembly://MsCorLib/System"
          xmlns:me="Me">

     
      <UI Name="VMCMusicArtistLister">

        <Locals>
          <a:ArtistList Name="TheArtistList" />
         
          <ScrollingHandler Name="ScrollingHandler" HandlerStage="Bubbled"/>
          <ScrollingData Name="ScrollingData" />
        </Locals>

        <Rules>
          <Changed Source="[TheArtistList.SongsChoice.Options]">
            <Actions>
              <PlaySound Sound="resx://VMCMusicArtistLister/gfmApps.VMC.Resources/Noise" />
            </Actions>
          </Changed>
        </Rules>

        <Content>
          <Panel Layout="Form">
            <Children>
              <Text Name ="Header" Content="VMCMusicArtistLister" Color="LightBlue" >
                <LayoutInput>
                  <FormLayoutInput Left="Parent,.05" Top="Parent,.03" />
                </LayoutInput>
              </Text>

              <me:SimpleScroller1 Name="ScrollArtists" MySource="[TheArtistList]" MyChoice="[TheArtistList.ArtistsChoice]" >
                <LayoutInput>
                  <FormLayoutInput Left="Parent,.05" Top="Parent,.10" />
                </LayoutInput>
              </me:SimpleScroller1>
              
            </Children>
          </Panel>
        </Content>

      </UI>

      <UI Name="SimpleScroller1">
        <Properties>
          <a:ArtistList Name="MySource" a:ArtistList="$Required" />
          <Choice Name="MyChoice" Choice="$Required" />
        </Properties>

        <Locals>
          <ScrollingHandler Name="ScrollingHandler" />
          <ScrollingData Name="ScrollingData" />
         
          <MouseWheelHandler Name="WheelHandler"/>
        </Locals>

        <Rules>
          <Default Target="[ScrollingHandler.ScrollingData]" Value="[ScrollingData]"/>
          <Default Target="[ScrollingData.Repeater]" Value="[SimpleRepeater]"/>
        </Rules>

        <Content>
          <Scroller Name="MyScroller" Orientation="Vertical" FadeSize="10" MaximumSize="0,550" ScrollingData="[ScrollingData]">
            <Children>
              <Repeater Name="SimpleRepeater" Source="[MyChoice.Options]">
                <Layout>
                  <FlowLayout Orientation="Vertical" Spacing="2,0"/>
                </Layout>

                <Content>
                  <me:ShowItem1 MySource="[MySource]" MyDataItem="[RepeatedItem!cor:String]" />
                </Content>
              </Repeater>
            </Children>
          </Scroller>
        </Content>
      </UI>

      <UI Name="ShowItem1">
        <Properties>
          <a:ArtistList Name="MySource" a:ArtistList="$Required" />
          <cor:String Name="MyDataItem" cor:String="$Required" />
        </Properties>

        <Locals>
          <ClickHandler Name="Clicker"/>
        </Locals>

        <Rules>
          <Default Target="[Input.KeyInteractive]" Value="true" />

          <Condition Source="[Clicker.Clicking]" SourceValue="true" >
            <!--Order Matters!-->
            <Actions>
              <Set Target="[Label.Color]" Value="Firebrick" />
            </Actions>
          </Condition>
          <Changed Source="[Clicker.Invoked]">
            <Actions>
              <Invoke Target="[MySource.Clicked1]" SelectedArtist="[MyDataItem]" />
            </Actions>
          </Changed>

          <Condition Source="[Input.KeyFocus]" SourceValue="true">
            <Actions>
              <Set Target="[Label.Color]" Value="Yellow" />
            </Actions>
          </Condition>

        </Rules>

        <Content>
          <Text Name="Label" Content="[MyDataItem]" Color="White"/>
        </Content>
      </UI>

    </Mcml>

    and now the new page
    VMCMusicArtistListerSongs.mcml
    ------------------------------------
    <Mcml xmlns="http://schemas.microsoft.com/2006/mcml"
          xmlns:a="assembly://VMCMusicArtistLister,Version=1.0.0.0,Culture=neutral,PublicKeyToken=771db207fea5dc69/gfmApps.VMC"
          xmlns:cor="assembly://MsCorLib/System"
          xmlns:me="Me">

      <UI Name="SongsList">
        <!--The properties comes from the c# file session.GotoPage property parameter-->
        <Properties>
          <a:ArtistList Name="ArtistList" a:ArtistList="$Required" />
          <cor:String Name="SelectedArtist" cor:String="$Required" />
          <Choice Name="SongsChoice" Choice="$Required" />
        </Properties>
        <Content>
          <Panel Layout="Form">
            <Children>
              <Text Name ="Header" Content="VMCMusicArtistLister" Color="LightBlue" >
                <LayoutInput>
                  <FormLayoutInput Left="Parent,.05" Top="Parent,.03" />
                </LayoutInput>
              </Text>
              <Text Name="AS" Content="[SelectedArtist]" Color="Yellow" >
                <LayoutInput>
                  <FormLayoutInput Left="Parent,.05" Top="Parent,.1" />
                </LayoutInput>
              </Text>
              <me:SimpleScroller2 Name="ScrollSongs" MySource="[ArtistList]" MyChoice="[SongsChoice]">
                <LayoutInput>
                  <FormLayoutInput Left="Parent,.55" Top="Parent,.10" />
                </LayoutInput>
              </me:SimpleScroller2>
            </Children>
          </Panel>
        </Content>
       
      </UI> 
     
     
      <UI Name="SimpleScroller2">
        <Properties>
          <a:ArtistList Name="MySource" a:ArtistList="$Required" />
          <Choice Name="MyChoice" Choice="$Required" />
        </Properties>

        <Locals>
          <ScrollingHandler Name="ScrollingHandler" />
          <ScrollingData Name="ScrollingData" />
        </Locals>

        <Rules>
          <Default Target="[ScrollingHandler.ScrollingData]" Value="[ScrollingData]"/>
          <Default Target="[ScrollingData.Repeater]" Value="[SimpleRepeater]"/>
        </Rules>

        <Content>
          <Scroller Name="MyScroller" Orientation="Vertical" FadeSize="10" MaximumSize="0,550" ScrollingData="[ScrollingData]">
            <Children>
              <Repeater Name="SimpleRepeater" Source="[MyChoice.Options]">
                <Layout>
                  <FlowLayout Orientation="Vertical" Spacing="2,0"/>
                </Layout>

                <Content>
                  <me:ShowItem2 MySource="[MySource]" MyDataItem="[RepeatedItem!cor:String]" />
                </Content>
              </Repeater>
            </Children>
          </Scroller>
        </Content>
      </UI>

      <UI Name="ShowItem2">
        <Properties>
          <a:ArtistList Name="MySource" a:ArtistList="$Required" />
          <cor:String Name="MyDataItem" cor:String="$Required" />
        </Properties>

        <Locals>
          <ClickHandler Name="Clicker"/>
        </Locals>

        <Rules>
          <Default Target="[Input.KeyInteractive]" Value="true" />

          <Condition Source="[Clicker.Clicking]" SourceValue="true" >
            <Actions>
              <Set Target="[Label.Color]" Value="Firebrick" />
            </Actions>
          </Condition>
          <Changed Source="[Clicker.Invoked]">
            <Actions>
              <Invoke Target="[MySource.Clicked2]" SelectedTrack="[MyDataItem]" />
            </Actions>
          </Changed>

          <Condition Source="[Input.KeyFocus]" SourceValue="true">
            <Actions>
              <Set Target="[Label.Color]" Value="Yellow" />
            </Actions>
          </Condition>

        </Rules>

        <Content>
          <Text Name="Label" Content="[MyDataItem]" Color="White"/>
        </Content>
      </UI>

    </Mcml>

    Well, it seems to work. Could probably be better structured as per StepbyStep or Z, but it'll do for me for now.

    If you want the complete solution file, please email me.



    Gordon: Has reached the end!
  •  04-29-2007, 4:44 AM 3094 in reply to 3090

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    The reason I suggested a 'More With This' addin is quite simple.

    The user already HAS the ability to look at their WMP library by Artist - it's a basic function of the 'Music' menu. They can also play those songs. So really, you've spent a lot of time re-inventing this basic functionality.

    The only NEW functionality you've created is the ability to make an 'artist playlist' - and why I can't see why this is all that much easier than just searching for an artist and pressing 'play', it's obviously something you feel you need.

    So you create a 'More With This' addin for the ARTIST. This allows you to simply press 'i' or right click, choose 'More..' and press 'Create Artist Playlist'. You don't need to spend so much time trying to put together a UI to search through an artist list...you just write a very basic piece of MCML to say 'Success' or 'Failure' and a simple C# class to create the playlist.

    It would save you vast amounts of time and would stop your program from having a different interface style to the rest of Media Center. Your method, while obviously an excellent piece of practise with MCML, just makes more work for you and more learning for the user.

    If you check the SDK, you can create a More With This addin for an artist. You can also do it for songs, genres, playlists and albums - not to mention images and videos.

    This means you basically need NO UI to do this playlist trick - which is franky easier on you and the user.


    100 downloads a day for Yougle Vista - goin' allright!

    Check out http://www.thedigitallifestyle.com/cs/Blogs/developer/default.aspx and http://www.push-a-button.com.au/products/mce
  •  04-29-2007, 2:26 PM 3096 in reply to 3094

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    Actually, I find that whatever Artist the vmc ui is picking up is related to the album artist. As the post in TGB makes clear is that many albums have contributing artists. For example compilations. My app picks up all the artists listed in the tag Artist tag, rather than as seems with vmc the albumartist tag. This is the point of the app.

    So actually, I haven't spent a lot of time re-inventing functionality. And if I had, what's it to you?

    To be honest, your arrogance is really starting to piss me off. get off your pedestal - it's not actually that high.






    Gordon: Has reached the end!
  •  04-29-2007, 3:34 PM 3097 in reply to 3096

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    Hehe - I don't mean to be arrogant, I'm just a sickler for efficiency more than anything else. I'm just getting a number of questions lately asking about functionality that Media Center already has. And you saw the length of the discussion with David - of course I was starting to sound annoyed :)

    Ahh, so your addin does pick up extra information other than simply the stuff that shows up when you sort by Artist in the Music list. In that case, I understand why you wrote the plugin. I just couldn't figure out why it's was useful. Now I know. I apologise if I came off particularly badly.

    And I'm not trying to be snooty when I'm suggesting other features or things for your program - I don't mean to be. I'm just unsure of what your intentions are with this. If you had planned on producing this as a real product available to the public, my suggestions were just that - suggestions for functionality that your users will quite likely be whining about sooner or later :).

    Anyway, as to your questions...

       There's no trouble at all with two scrollers in a single UI - although I'd seperate them simply to make the code neater. But if you were looking two scrollers in a single 'page' or 'screen' in Media Center, you can have as many as you like - you just need to check the navigation to make sure it works.

       This is kinda easy to see, because multiple scrollers are used all over the place in Media Center. Most of the menus - particularly the music ones - have a horizontal scroller up the top and a vertical or horizontal one below.

       You just have to keep them seperate, because if they take up the same place on the screen, things are going to get tricky for the mouse and remote navigation. I think you were brining one scroll up on top of another one - and THAT is where all hell breaks loose.

       If you do overlay like this, you'll need to look out for is the 'z-order' of your elements. Your elements are drawn in a certain order - usually top-to-bottom. This is also the order of your input focus. So if you ARE going to overlay elements, you'll need to make sure that you also get the order correct.

       If you did want to try to make a new user interface element appear over another, you need to make sure that the new one is going to be above it. When you want to show this overlay UI, you set it's visible property to true and (sometimes) Invoke the 'NavigateInto' command - this changes the current focus to your UI.

       The Visible property is an important one. When an object has an alpha of 0, it is still going to react to the keyboard or mouse, so if you are going to overlay two elements that both accept input, you'll need to make sure that the topmost one is set to visible="false". Then, when you want it to appear, you set it's visible to true.

       Oh, and when you do this, the 'Alpha' animations will not run. Instead, setting items to visible and not visible fires off the Hide and Show animations - the same ones that run when your Media Center application first appears on-screen and when you navigate away from the page.

       But there's no problem in creating your app as two seperate UI's. In the end, it's often cleaner and easier to debug your code, as well as giving you 'back' button compatibility. I think for this application, two seperate pages (the way you have it in your 2nd example) is certainly the way to go.

       Making UI's appear above others is mainly for 'popups' or other effects where you want to bring up something over the background, but not replacing the background. These are usually small, like status text when loading something or for context-menus.

       And to be honest, even when I do a trick like this where the popup item is complicated (such as the 'search' tab in Yougle2) I often define the actual popup UI in a seperate file, just to keep everything seperate.


    100 downloads a day for Yougle Vista - goin' allright!

    Check out http://www.thedigitallifestyle.com/cs/Blogs/developer/default.aspx and http://www.push-a-button.com.au/products/mce
  •  04-30-2007, 1:58 AM 3099 in reply to 3097

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    Thanks Ig. I appreciate your taking time out to explain what was happening with my initial idea of two scrollers. And thanks for explaining where you were coming from.

    :)



    Gordon: Has reached the end!
  •  05-01-2007, 6:02 PM 3114 in reply to 3099

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    This probably won't be a concern with your application, but I thought I'd bring it to your attention.

    http://discuss.mediacentersandbox.com/forums/thread/3110.aspx

    It's a problem I've discovered with Media Center and the Windows Media Player SDK, and a step you can take to resolve it.

    Basically, the app loses it's connection to the Media Player SDK. It only seems to crop up when running release code - and probably only in threads too. Still, just in case you find that you are having some trouble in any proper release installation, this may be why.


    100 downloads a day for Yougle Vista - goin' allright!

    Check out http://www.thedigitallifestyle.com/cs/Blogs/developer/default.aspx and http://www.push-a-button.com.au/products/mce
  •  05-01-2007, 8:02 PM 3115 in reply to 3114

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

             //not sure how best to pass the session object to my other class?
            public static HistoryOrientedPageSession S_Session
            {
                get { return s_session; }
            }

       This is a valid way of passing the session to other object, but there are simpler ones. You don't need to worry about creating a property like this - you only really need to create properties when you are going to read the value from MCML.

       I personally use 'static' variables.

       These variables are a little bit unusual. Normally, when you give a class a member like 'public String Name;', this will create a Name property for every single object of this type you create.

       So if you write the following code...

          MyObject Ob1 = new MyObject();

          MyObject Ob2 = new MyObject();

          Ob1.Name = "Hello";

          Ob2.Name = "There";

      then Ob1 will have a Name property of "Hello" and Ob2 will have a property of "There".

       But if you declare the variable as a static variable, it will be shared across every instance of the class. So if we had Name as a static and ran the above example, both Ob1 and Ob2 will have a Name attribute of "There" - since both of them point to exactly the same string.

       And there's one other trick with statics. You don't actually need an instance of the class to access the static variable. You can just use the NAME of the class.

       So rather than saying...

          MyObject Ob1 = new MyObject();

          Ob1.Name = "Hello";

       you can instead simply write...

          MyObject.Name = "Hello";

       I use this trick to hold both my Session and AddInHost objects in my IAddinModule class (the main class that Media Center actually runs - the one that Visual Studio generates for you when you start an application).

      
        public class BaseAddin : IAddInModule, IAddInEntryPoint
        {
              public static AddInHost Host;
              public static HistoryOrientedPageSession Session;

              public void Launch(AddInHost host)
             {

                Host = host;
                Session = new HistoryOrientedPageSession();
                Session.GoToPage("resx://MCMLookalike/MCMLookalike.Resources/Default");
             }

             ...

         }

       So then you can access your Host and Session object simply by saying 'BaseAddin.Host' or 'BaseAddin.Session' at any point in your program.

       Someone may have a better idea - but this is my solution.


    100 downloads a day for Yougle Vista - goin' allright!

    Check out http://www.thedigitallifestyle.com/cs/Blogs/developer/default.aspx and http://www.push-a-button.com.au/products/mce
  •  05-02-2007, 9:40 AM 3128 in reply to 3115

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    Yeah, that's good. I should have thought of that.



    Gordon: Has reached the end!
  •  05-21-2007, 7:04 AM 3396 in reply to 3090

    Re: MCML - The Basic Apps - A Real One - VMCMusicArtistLister

    Hi Gordon

    i came across your WMC application on VMCMusicArtistLister and i'm very anxious to have the entire C# and MCML source codes. Pls email to me at akai80@yahoo.com

    Actually i'm designing a Media Center application where users can browse the Recorded TV folder to select a video file to play. How do i encode my application to show the list of files in this Recorded TV folder. I guess you might have some valuable advice for me.

    Cheers

Page 1 of 2 (16 items)   1 2 Next >
View as RSS news feed in XML
Powered by Community Server, by Telligent Systems