Jim
Jim

Reputation: 191

WPF Mediaelement mediaopened event not firing from code behind but does from button click handler

First post so be gentle and sorry for a long post but wanted to provide as much detail as I could.

I have a MediaElement control inside a usercontrol with the LoadedBehaviour property set to manual, see below. When I click on the 'Open' button the handler code includes playing the media so that I can ready the duration properrty in the MediaOpened event handler, which it does successfully. The MediaOpened handler stops the playing when I'm just requiring the media length.

I also want to load a playlist at the start of the program and fill a datagrid with information, one element being the length of the media.

XAML

    <MediaElement Grid.Row="5" Name="MediaEL" Grid.ColumnSpan="6" MediaOpened="MediaEL_MediaOpened"  LoadedBehavior="Manual" Height="169" />

    <DataGrid Grid.Row="1" Grid.ColumnSpan="6"  Name="dgPlayList" AutoGenerateColumns="False" Height="300" >
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Position}" Header="#" Width="30"/>
            <DataGridTextColumn Binding="{Binding Title}" Header="Title" Width="182"/>
            <DataGridTextColumn Binding="{Binding Time}" Header="Time" Width="50"/>
            <DataGridCheckBoxColumn Binding="{Binding Dnp}" Header="Dnp" Width="35"/>
            <DataGridTextColumn Binding="{Binding Location}" Visibility="Hidden" />
        </DataGrid.Columns>
    </DataGrid>

C#

    private void btnOpen_Click(object sender, RoutedEventArgs e)  
    {  
        System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();  

        if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)  
        {  
            MediaEL.Source = new Uri(ofd.FileName);
            btnPlay.IsEnabled = true;
            MediaEL.Visibility = Visibility.Hidden;
            SettingTime = true;
            MediaEL.Play();
        }
    }

    private void MediaEL_MediaOpened(object sender, RoutedEventArgs e)
    {
        if (MediaEL.NaturalDuration.HasTimeSpan)
        {
            TimeSpan ts = MediaEL.NaturalDuration.TimeSpan;
            Length.Content = FormatLength(ts.TotalSeconds);  // make it look like 00:00:00
            seekBar.Maximum = ts.TotalSeconds;
            seekBar.SmallChange = 1;
            seekBar.LargeChange = Math.Min(10, ts.Seconds / 10);
        }
        if (!SettingTime)
            timer.Start();
        else
        {
            SettingTime = false;
            MediaEL.Stop();
            MediaEL.Visibility = Visibility.Visible;
            MediaEL.Close();
        }
    }

dgPlayList.ItemsSource = LoadPlayListData();

is called in the window loaded method.
I have commented out in the method below the foreach statement until I get one working.

Now the PROBLEM is when trying to get the media length to fill the datagrid time column the MediaOpened event does NOT fire and I cannot see why not and have exhausted searches on the subject.
Any thoughts would be most appreciated !
Thanks, Jim

C#

    private ObservableCollection<PlayListEntry> LoadPlayListData()
    {
        var playListEntries = new ObservableCollection<PlayListEntry>();
        var position = 1;
        var bPlay = false;

        var doc = new XmlDocument();
        doc.Load(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase) + @"/mpcplaylist.xml");

        var root = doc.DocumentElement;
        var nodes = root.SelectNodes("/playlist/media");

        XmlNode node = nodes[0];

        if (node.InnerXml.Contains("title"))
        {
            var xmlElement = node["title"];
            if (xmlElement != null)
                Title = xmlElement.InnerText;
        }

        if (node.InnerXml.Contains("artist"))
        {
            var xmlElement = node["artist"];
            if (xmlElement != null)
                Artist = xmlElement.InnerText;
        }

        if (node.InnerXml.Contains("location"))
        {
            var xmlElement = node["location"];
            if (xmlElement != null)
                Location = xmlElement.InnerText;
        }

        if (node.InnerXml.Contains("include"))
        {
            var xmlElement = node["include"];
            if (xmlElement != null)
                Include = xmlElement.InnerText;
        }

        if (Include == "No")
            bPlay = true;
        else
            bPlay = false;

        //foreach (XmlNode node in nodes)
        //{
        //    if (node.InnerXml.Contains("title"))
        //    {
        //        var xmlElement = node["title"];
        //        if (xmlElement != null)
        //            Title = xmlElement.InnerText;
        //    }

        //    if (node.InnerXml.Contains("artist"))
        //    {
        //        var xmlElement = node["artist"];
        //        if (xmlElement != null)
        //            Artist = xmlElement.InnerText;
        //    }

        //    if (node.InnerXml.Contains("location"))
        //    {
        //        var xmlElement = node["location"];
        //        if (xmlElement != null)
        //            Location = xmlElement.InnerText;
        //    }

        //    if (node.InnerXml.Contains("include"))
        //    {
        //        var xmlElement = node["include"];
        //        if (xmlElement != null)
        //            Include = xmlElement.InnerText;
        //    }

        //    if (Include == "No")
        //        bPlay = true;
        //    else
        //        bPlay = false;


            MediaEL.Source = new Uri(Location);

            SettingTime = true;

            MediaEL.Play();

            Medialength = Length.Content.ToString();

            playListEntries.Add(new PlayListEntry()
            {
                Dnp = bPlay,
                Position = position++,
                Time = Medialength,
                Title = Title,
                Location = Location
            });


        //}

        return playListEntries;
    }

Upvotes: 3

Views: 4269

Answers (2)

Jim
Jim

Reputation: 191

Solution was...

I grab the first entry from the xml playlist and set the source property then call the play method to get the duration. Now in the Media Opened event I then grab the next entry and do the same until I have the duration for all of the media items in the list.

That was the key have the media opened event get the next entry after the first had been handled.

That said I have another issue with threading and the control but I will create a new post for that.

Thanks, Jim

Upvotes: 2

Sheridan
Sheridan

Reputation: 69959

Ok, so I haven't managed to find a complete solution to my version of your problem, but I have determined what is causing my problem with the MediaPlayer object. My application (and internal media player) was all working just fine, but it stopped working after the permissions on the folder that contains the audio were changed.

The folder was changed to permit only read access, so the mediaPlayer should still have been able to access the files. It seemed however, as though it required a higher level of permission before it could open any file. I tested this using WindowsIdentity.Impersonate method, giving full permissions to the call to the MediaPlayer.Open method, but there was no change.

Finally, I tried passing a path for an audio file on the local file system to the MediaPlayer.Open method and hey presto, it all worked again as before! Maybe you should try this last step to see if your problem is also caused by security permissions.

UPDATE >>

Yep, it turned out to be a permissions error. The IT department messed up my access rights, so that's why the MediaPlayer (or application, which inherited my access permissions) could not open the audio file. After giving me the correct rights, the MediaPlayer began to work just fine again.

I hope that this helps.

Upvotes: 0

Related Questions