Microsoft.Toolkit.Win32
Microsoft.Toolkit.Win32 copied to clipboard
MediaPlayerElement needs a better sample
I'm submitting a...
Sample app request
Current behavior
MediaPlayerElement has a short sample auto playing a web video
Expected behavior
MediaPlayerElement needs also a sample demonstrating how to play / pause / stop / change volume and set / get playing position from code. Because there is no Play() method for example. And the only documentation I find is about the UWP version which seems to have a play method
https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Controls.MediaPlayerElement
which states:
You can create your own media transport controls by setting AreTransportControlsEnabled to false, and using the Play and Pause methods on MediaPlayer. You can also control a rich set of properties by using the underlying MediaPlayer such as Position, Volume, IsMuted, IsLoopingEnabled, and PlaybackRate.
Environment
Nuget Package(s): Microsoft.Toolkit.Wpf.UI.Controls Package Version(s): 6.0.0-preview3
Windows 10 Build Number:
- [X] October 2018 Update (17763)
App min and target version:
- [X] October 2018 Update (17763)
Device form factor:
- [X] Desktop
Visual Studio
- [X] 2019 (version: )
@Symbai, the MediaPlayerElement is just a host, as the documentation calls out for it, you need to access Play and other methods of it's MediaPlayer property/reference.
@michael-hawker MediaPlayer property throws a NullReferenceException all the time when being used in code. Which was the reason why I've asked for a sample because I thought I might be doing something wrong.
XAML code taken from the only WPF sample in this repo
<controls:MediaPlayerElement x:Name="mediaPlayerElement"
Source="https://mediaplatstorage1.blob.core.windows.net/windows-universal-samples-media/elephantsdream-clip-h264_sd-aac_eng-aac_spa-aac_eng_commentary-srt_eng-srt_por-srt_swe.mkv"
AutoPlay="True" Margin="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AreTransportControlsEnabled="True" />
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Microsoft.Toolkit.Wpf.UI.Controls.MediaPlayerElement.MediaPlayer.get returned null.
@marb2000 @ocalvo @azchohfi any thoughts with your expertise in this area? I thought the UWP MediaPlayerElement is supposed to have it's own MediaPlayer instance already initialized, so it should be retrievable here, eh? Debugging the sample app seems to show this as the case as I see the MediaPlayer instance on the ChildInternal UWP object.
I thought maybe it'd be because the Bind
method sets the default to one-way binding here. But changing that doesn't seem to impact the property.
What do we need to change to get this to bubble up?
@ocalvo Alex and I took a look it seems to be an initializing timing problem? The MediaPlayer
instance is null
in OnInitialized
in the wrapper, so the binding fails. We tried setting up the binding in the Loaded event for the UwpControl
itself where we see the MediaPlayer instance, but this also failed. For some reason the WPF DependencyProperty is always returning null for MediaPlayer.
Any thoughts on what's happening here? Thanks!
@marb2000 @ocalvo @azchohfi any thoughts with your expertise in this area? I thought the UWP MediaPlayerElement is supposed to have it's own MediaPlayer instance already initialized, so it should be retrievable here, eh? Debugging the sample app seems to show this as the case as I see the MediaPlayer instance on the ChildInternal UWP object.
I thought maybe it'd be because the
Bind
method sets the default to one-way binding here. But changing that doesn't seem to impact the property.What do we need to change to get this to bubble up?
My understanding is that it will only have its own instance when used from the WinUI Xaml compiler as only the Xaml compiler will initialize the media player instance (the WPF Xaml compiler does not count)
I think you will need to modify the wrapper to initialize the media player instance if Source property is set.
Any update on this? I would really love to use this control but failing to access the mediaplayer property makes it impossible.
@Symbai, the bug is in the backlog. At this time, we don't really know when we will able to fix it.
We've pushed a fix for the MediaPlayer element being null. It's now possible to access. If anyone wants to improve the sample, please let us know. Though we need to resolve #197 first.
Finally, first time the mediaplayer becomes usable for offline purposes. Thank you so much ❤
//edit: Hm, I've tried the fix and mediaplayer property is not null anymore but all sub properties are if no source is specified in XML.
<Grid>
<controls:MediaPlayerElement
x:Name="mediaPlayerElement"
Margin="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AreTransportControlsEnabled="True"
Loaded="mediaPlayerElement_Loaded" />
</Grid>
Its fixed by changing XML and adding the source value as in demo example:
<Grid>
<controls:MediaPlayerElement
x:Name="mediaPlayerElement"
Margin="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AreTransportControlsEnabled="True"
Loaded="mediaPlayerElement_Loaded"
Source="https://mediaplatstorage1.blob.core.windows.net/windows-universal-samples-media/elephantsdream-clip-h264_sd-aac_eng-aac_spa-aac_eng_commentary-srt_eng-srt_por-srt_swe.mkv" />
</Grid>
Thanks for testing it out @Symbai, if you set the source in the code-behind before looking at the MediaPlayer's properties, do they appear then? I'm not sure what the regular behavior of MediaPlayer is, so maybe it needs a source before the properties are setup?
MediaPlayer doesn't seem to have a Play() or Pause() method or anything like that. Am I looking at the wrong property?
@reinux Another massive oversight. The methods that you want are on this internal property and the wrapper class has not exposed them. https://github.com/windows-toolkit/Microsoft.Toolkit.Win32/blob/1bc631b12a23b04acbcc38e7f682cb780d88b540/Microsoft.Toolkit.Win32.UI.Controls/Interop/WinRT/MediaPlayer.cs#L14
A proposed solution for the null reference exception.
Set a dummy source ( 0 seconds duration ) instead of none. Set the IsDummySource property to true. When you change to a real source set IsDummySource to false.
This will not work currently as all wrapped controls are inherently broken both in terms of MVVM binding and changing properties in code. I have fixed the Bind method of WindowsXamlHostBase which is at fault and will supply a pull request in the next couple of days.
The code to add to MediaPlayerElement
private bool hasLoaded;
//add loaded handler to constructor
protected MediaPlayerElement(string typeName)
: base(typeName)
{
Loaded += MediaPlayerElement_Loaded;
}
private void MediaPlayerElement_Loaded(object sender, RoutedEventArgs e)
{
if (!hasLoaded && IsDummySource)
{
EnableDisablePlayButton(false);
hasLoaded = true;
}
}
private void EnableDisablePlayButton(bool enabled)
{
MediaPlayer.SystemMediaTransportControls.IsPlayEnabled = enabled;
}
public bool IsDummySource
{
get { return (bool)GetValue(IsDummySourceProperty); }
set { SetValue(IsDummySourceProperty, value); }
}
public static readonly DependencyProperty IsDummySourceProperty =
DependencyProperty.Register("IsDummySource", typeof(bool), typeof(MediaPlayerElement), new PropertyMetadata(false,
(depObj, dp) =>
{
var isDummySource = (bool)dp.NewValue;
var mediaPlayerElement = depObj as MediaPlayerElement;
if (mediaPlayerElement.hasLoaded)
{
mediaPlayerElement.EnableDisablePlayButton(!isDummySource);
}
}));
Hello,
I have ran into an issue where MediaPlayerElement instance returns null when MediaPlayerElement.MediaPlayer is called once again.
Am I missing something?