.NET MAUI, is MediaElement's "Source" attribute bindable?

304 views Asked by At

I'm trying to not hardcode the value for the Source attribute for the MediaElement using XAML (as opposed to C#).

I have this code:

            <!-- Displays "embed://file.mp4" -->
            <Label Text="{Binding Filename}" FontSize="Large" Padding="20"/>

            <!-- Doesn't work. -->
            <toolkit:MediaElement Source="{Binding Filename}"
                                  ShouldShowPlaybackControls="True"
                                  Aspect="AspectFill" />

            <!-- Has SAME VALUE, but does work -->
            <toolkit:MediaElement Source="embed://file.mp4"
                                  ShouldShowPlaybackControls="True"
                                  Aspect="AspectFill"/>

I guess that the Source attribute isn't "bindable" or something (I'm sorry I'm new here). But if it's not bindable, then what are devs supposed to do?

If the answer's in the docs, then I can't find it.


EDIT: of course it's more complicated than the text above...

I'm actually passing the filename to the page that's displaying the media from another page. See, the user selects a video to watch, I grab the Video object and pass video.filename to the new page, which will display the video.

My original idea was this. First, pass the video filename from the Page where the user selects a Video:

[RelayCommand]
private async Task NavigateToPlayMediaPage(Video video)
{
   string str = "embed://" + video.VideoFilename;  // "ThrowSource" is a string prop
   await Shell.Current.GoToAsync($"//{nameof(PlayMediaPage)} ThrowSource={str}");
}

We catch the string on the Page where we display the Media, and we do this in the Xaml:

            <toolkit:MediaElement Source="{Binding CatchSource}"
                                  ShouldShowPlaybackControls="True"
                                  Aspect="AspectFill" />

Of course, it turns out that Source takes an object of type `MediaSource'.

OK. So what I could do is create the MediaSource object from the passed-filename string. I could create an "Appearing" method (that runs before the Xaml). In that "Appearing" method, I could create the MediaSource:

using CommunityToolkit.Maui.Views;

namespace ems_mobile.ViewModel;

[QueryProperty("CatchSource","ThrowSource")]
public partial class PlayMediaPageViewModel : ObservableObject
{
    [ObservableProperty]
    string catchSource;

    [RelayCommand]
    private async Task Appearing()
    {
        var mediaSource = MediaSource.FromResource(CatchSource);
    }
}

And then I could use that MediaSource object in the Xaml:

            <toolkit:MediaElement Source="{Binding mediaSource}"
                                  ShouldShowPlaybackControls="True"
                                  Aspect="AspectFill" />

Alas, that doesn't work. I'm just getting a white screen. No player. No error. The problem is in the "Appearing" method I don't actually have access to the passed-string. I guess "Appearing" methods don't get passed strings or something.

=======================================================================

EDIT: Getting weird exception. If I can figure this out, I should be good.

I'm passing the Media Source object from the SelectMedia page to the ViewMediaPage. It's passing correctly with the correct values.

Here it is, enjoying itself in the method where it gets passed: enter image description here

And here it is on the other side, the cheeky bugger, values intact: enter image description here

Here's the xaml -- it looks good to me: enter image description here

The only problem... when I get into the ViewMediaPage, this happens: enter image description here

================================================================ FINAL EDIT how Ï got it to work.

I had that exception message you must implement IConvertible. So I did.

Here's a link that explains it. I had created the MediaElement object needed for the Source, only I didn't pass it from the previous Page correctly.

That link shows a great way to pass as many objects as you like from one page to another, pretty hassle-free. The only problem is you can't access the passed objects from an Appearing method because the Appearing method runs before the implementation of the IConvertible interface, which does the "catching" of the objects.

1

There are 1 answers

0
Kapusch On

Using .NET MAUI Community Toolkit, you could achieve this with an ObservableProperty in your ViewModel:

[ObservableProperty]
string audioURL;

And then add the Data Binding logic from your View:

MyMediaElement.Bind(
        MediaElement.SourceProperty,
        nameof(MyViewModel.AudioURL),
        convert: (string url) => MediaSource.FromUri(url));

If you are interested to see it in action, I have written a series of articles about the MediaElement. You can start from here.