Search code examples
mvvm-lightwindows-phone-7mediaelement

Play / pause mp3 files in Windows Phone MVVM application


I am trying to play small mp3 file in my Windows Phone 7.5 MVVM application (MVVM Light is used).

I am trying:

1st. To use SoundEffect:

SoundEffectInstance instance;
SoundEffect effect = SoundEffect.FromStream(stream);
instance = effect.CreateInstance();
FrameworkDispatcher.Update();
instance.Play();

Problem: only .wav files allowed.

2nd. To use Microsoft.Xna.Framework.Media.Song:

Microsoft.Xna.Framework.Media.Song song = Microsoft.Xna.Framework.Media.Song.FromUri("name", new Uri("someUri"));

Problem: file is stored in the IsolatedStrorage and we need to know the full path to the file.

Suggested hint:

string path = stream.GetType().GetField("m_FullPath", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(stream).ToString();

is not working.

3d. To use standard MediaElement.

Problem: I need an access to the MediaElement control in the ViewModel which is not good from the MVVM view.

How to solve this issue?


Solution

  • One way to accomplish this in the MVVM style is to use the MVVM Light Messenger class to send play/pause messages from the viewmodel, which the view would subscribe to and receive.

    Say you have a pair of Buttons on your view for Play and Pause. You would drop an EventToCommand behavior on each of them in Expression Blend, and then you would bind them to a pair of RelayCommand properties in your viewmodel, one RelayCommand for Play, one for Pause. For example, in your viewmodel, you would have:

    public RelayCommand PlayCommand { get; private set; }
    public RelayCommand PauseCommand { get; private set; }
    

    The Play command would have the Messenger send a Play message, and the Pause command would send a Pause message. Each message would be its own simple class:

    public class PlayMessage { }
    public class PauseMessage { }
    

    Then, in the constructor of your viewmodel, you would create new RelayCommands for the two RelayCommand properties you created earlier that would have actions that have the Messenger send the messages:

    MyViewModel()
    {
        PlayCommand = new RelayCommand( () => SendPlayMessage() );
        PauseCommand = new RelayCommand( () => SendPauseMessage() );
    }
    
    private void SendPlayMessage()
    {
        Messenger.Default.Send<PlayMessage>( new PlayMessage() );
    }
    
    private void SendPauseMessage()
    {
        Messenger.Default.Send<PauseMessage>( new PauseMessage() );
    }
    

    Your view would then have the Messenger subscribe to both of these message types, and would have actions that would call the Play and Pause methods on the MediaElement:

    MyView()
    {
        Messenger.Default.Register<PlayMessage>
        (
            this,
            ( action ) => ReceivePlayMessage( action )
        );
        Messenger.Default.Register<PauseMessage>
        (
            this,
            ( action ) => ReceivePauseMessage( action );
        );
    }
    
    private void ReceivePlayMessage(PlayMessage msg)
    {
        myMediaElement.Play();
    }
    
    private void ReceivePauseMessage(PauseMessage msg)
    {
        myMediaElement.Pause();
    }
    

    Where myMediaElement is the name you give to the MediaElement in your view's xaml.