0
votes

I would like to play sounds, and display a progress bar below each sounds I'm displaying the current progress thanks to this in my VM: (source: http://dotnet.dzone.com/articles/playing-media-content-windows)

player.CurrentStateChanged += player_CurrentStateChanged;
[...]
 void player_CurrentStateChanged(object sender, RoutedEventArgs e)
    {
        var mediaPlayer = sender as MediaElement;
        if (mediaPlayer != null && mediaPlayer.CurrentState == MediaElementState.Playing)
        {
            var duration = mediaPlayer.NaturalDuration.TimeSpan.TotalSeconds;
            ThreadingHelper.ExecuteAsyncAction(() =>
                {
                    do
                    {
                        ThreadingHelper.ExecuteOnUiThread(() =>
                        {
                            Progress = mediaPlayer.Position.TotalSeconds * 100 / duration;
                        });
                        Thread.Sleep(10);
                    } while (IsPlaying);
                });
        }
    }

and xaml:

<!--TITLE-->
                <TextBlock Text="{Binding Sound.Libelle}"
                           Style="{StaticResource PhoneTextNormalStyle}"
                           TextWrapping="Wrap"/>

            <ProgressBar Height="20" Width="400" Value="{Binding Progress}"></ProgressBar>

The progress bar display correctly, problem is when I play a second sound, the first progress bar is also updated, due to binding with my Progress property.

I don't know how to prevent this behavior, any ideas are welcome.

EDIT: I forgot to mention that this behavior occurs only when I'm starting another sound while a first is playing. My first sound stop, the second start but both progress bar are updated

EDIT2: A little more code:

 private void PlaySong()
    {
        MediaElement player = null; // get the media element from App resources
        if (Application.Current.Resources.Contains("MediaPlayer"))
        {
            player = Application.Current.Resources["MediaPlayer"] as MediaElement;
        }
        if (player != null)
        {
            if (IsPlaying)
            {
                player.Stop();
                player.MediaEnded -= player_MediaEnded;
                player.CurrentStateChanged -= player_CurrentStateChanged;
            }
            else
            {
                player.Source = new Uri(Sound.Link, UriKind.Relative);
                player.Play();
                player.MediaEnded += (o, args) => player_MediaEnded(player, args);
                player.CurrentStateChanged += player_CurrentStateChanged;
                IsPlaying = true;
            }
        }            
    }

This is my PlaySong() method called onClick, who gets the unique MediaPlayer defined in my app.xaml. It play or stop according to current sound state.

This is my xaml, it's a template for a <ListBox> control bound to an ObservableCollection of SoundViewModel

<Button x:Name="SoundButton"
                Command="{Binding PlaySongCommand}"
                HorizontalAlignment="Stretch"
                Style="{StaticResource EmptyButtonStyle}">
            <StackPanel Margin="12,0,0,12">

                <!--TITLE-->
                <TextBlock Text="{Binding Sound.Libelle}"
                           Style="{StaticResource PhoneTextNormalStyle}"
                           TextWrapping="Wrap"/>

            <ProgressBar Height="20" Width="400" Value="{Binding Progress}"></ProgressBar>
        </StackPanel>
        <!-- LONG HOLD GESTION-->
        <toolkit:ContextMenuService.ContextMenu>
            <toolkit:ContextMenu Name="AllsoundMenu" IsZoomEnabled="True">
                <toolkit:MenuItem Header="Add to favorite" 
                                      Command="{Binding AddToFavoriteCommand}" />
                <toolkit:MenuItem Header="Add as a ringtone" Command="{Binding AddToRingtoneCommand}" />
            </toolkit:ContextMenu>
        </toolkit:ContextMenuService.ContextMenu>
    </Button>

So one ProgressBar/Sound and only one MediaElement in the app. Hope this helps you to see clearer.

Maybe I souldn't have only one MediaElement, but it seemed right to implement this way.

1
I'm a bit confused by your setup. Does you each player have it's own ProgressBar? If so, are do each Player/ProgressBar combo have its own viewmodel? If no to either of these questions, that would explain why you see the behavior you do.Joel Shea
OKay. Hmm actually I have only one Player, and multiple ProgressBar, maybe I should try to set up Player/ProgressBar combo ?Pierpowl
So just to make sure I'm understanding, how do you visually distinguish between your different ProgressBars and what they are associated too? Are they in a ItemsControl of some sort? Perhaps if you showed us more of your XAML, what you are trying to accomplish would be more clear...Joel Shea
Ok, I've added more code, hope this will help to understand what I tried to do ;)Pierpowl

1 Answers

0
votes

i think you should try to remove the handler from the 'player' object when the sound is not running. i hope it will help. like this:

 void player_CurrentStateChanged(object sender, RoutedEventArgs e)
    {
        var mediaPlayer = sender as MediaElement;
        if (mediaPlayer != null && mediaPlayer.CurrentState == MediaElementState.Playing)
        {
            var duration = mediaPlayer.NaturalDuration.TimeSpan.TotalSeconds;
            ThreadingHelper.ExecuteAsyncAction(() =>
                {
                    do
                    {
                        ThreadingHelper.ExecuteOnUiThread(() =>
                        {
                            //A list of values , nowPlay means that the sound you are playing
                            ProgressList[nowPlay] = mediaPlayer.Position.TotalSeconds * 100 / duration;
                        });
                        Thread.Sleep(10);
                    } while (IsPlaying);
                });

        }
    }

xaml:

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <phone:LongListSelector x:Name="MainLongListSelector" Margin="0,0,-12,0" ItemsSource="{Binding ProgressList}" SelectionChanged="MainLongListSelector_SelectionChanged">
            <phone:LongListSelector.ItemTemplate>
                <DataTemplate>
                  <StackPanel Margin="0,0,0,17">
                        <ProgressBar Height="20" Width="400" Value="{Binding Values}"/>
                  </StackPanel>
                </DataTemplate>
            </phone:LongListSelector.ItemTemplate>
        </phone:LongListSelector>
    </Grid>

ViewModel:

public class Progress : INotifyPropertyChanged
    {
        int _values;
        public int Values
        {
            get
            {
                return _values;
            }
            set
            {
                if (value != _values)
                {
                    _values = value;
                    NotifyPropertyChanged("Values");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

 public class MainViewModel : INotifyPropertyChanged
    {
        List<Progress> _progress = new List<Progress>();
        int _values = 100;
        public MainViewModel()
        {
            this.Items = new ObservableCollection<ItemViewModel>();
            _progress.Add(new Progress());
            _progress.Add(new Progress());
            _progress[0].Values = 50;
            _progress[1].Values = 100;

        }
     ...
     }