'MediaElement.SetSource()' isn't updating consistently - c#

My program should play a video when the user presses the 'Play' button. While it normally does this, the very first time they press the 'Play' button nothing will happen.
I have traced this bug back to the following code, which sets my MediaElement 'VideoPlayer':
public void playVideo_Tapped(object sender, TappedRoutedEventArgs e)
{
setUpVideo();
VideoPlayer.Play();
}
public async void setUpVideo()
{
if(vm == null) return;
StorageFile videoFile = vm.videoFile;
if (videoFile == null || !videoFile.ContentType.Equals("video/mp4")) return;
using (IRandomAccessStream fileStream = await videoFile.OpenAsync(FileAccessMode.Read))
{
VideoPlayer.SetSource(fileStream, videoFile.ContentType);
}
}
The culprit seems to be the 'SetSource()' method at the end. The only variable that changes from the first click of 'Play' to the next is the variable 'VideoPlayer.PlayToSource', which is changed from null to a real value.
(As a side note, the variable 'VideoPlayer.CurrentState' also changes from 'Closed' to 'Opening' but resets itself to 'Closed' before the second click. Only 'PlayToSource' changes the functionality.)
I figured that I could do a quick-fix by doing this in my first method:
setUpVideo();
setUpVideo();
VideoPlayer.Play();
Not great code but it ought to set things straight, right? Nope! This causes a NullReferenceException. On the second call to 'setUpVideo()' I find that 'PlayToSource' still has a value and 'VideoPlayer.CurrentState' is still set to 'Opening'... which somehow triggers the NullReferenceException.
I'm expecting the solution to be one of the following things:
1.) Set 'VideoPlayer.PlayToSource' on the first click before calling 'SetSource'.
2.) In the quick-fix, set 'VideoPlayer.CurrentState' back to 'Closed' in between calls.
3.) Some other thing that mimics what the first click is doing.
Of course, both of my ideas involve changing a read-only variable. Which is where I'm getting stuck. I'll include the .xaml code for good measure, but I'm confident that it's the method 'SetSource' that's the root of my troubles:
<Grid x:Name="VideoViewerParentGrid" Background="DarkGreen" Height="{Binding VideoViewerParentGridHeight }" Width="{Binding VideoViewerParentGridWidth}">
<MediaElement x:Name="VideoPlayer" HorizontalAlignment="Center" VerticalAlignment="Bottom" Stretch="Uniform"
Visibility="{Binding VideoVisibility, Converter={StaticResource visibilityConverter}}"/>
<Button Style="{StaticResource BackButtonStyle}" Tapped="VideoViewerClose_Tapped" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Button Name="Play_Button" Content="Play Video" FontSize="26" Tapped="playVideo_Tapped"
VerticalAlignment="Top" HorizontalAlignment="Left" Height="60" Width="180" Margin="0,80,0,0"/>
</Grid>
---- UPDATE ----
Some more poking has revealed that on the first click 'VideoPlayer.CurrentState' never reaches the 'Playing' state, instead going from 'Opening' right back to 'Closed'. It does not do this on any subsequent clicks for as long as the program is running. Still investigating the cause of this.

You are missing the "await" keyword. Do this:-
await setUpVideo();

Short version, this issue is fixed by changing this:
using (IRandomAccessStream fileStream = await videoFile.OpenAsync(FileAccessMode.Read))
{
VideoPlayer.SetSource(fileStream, videoFile.ContentType);
}
...to be this:
IRandomAccessStream fileStream = await videoFile.OpenAsync(FileAccessMode.Read);
VideoPlayer.SetSource(fileStream, videoFile.ContentType);
Longer version, my code was failing because of the error "mf_media_engine_err_src_not_supported hresult - 0xc00d36c4", which was closing my MediaElement instead of playing it. This was happening because when I left the 'using' block of code the 'IRandomAccessStream' would close in the middle of my reading of the file. I'm not 100% clear why it gets through the whole thing after the first run of the code, but at least it now works reliably.
I've also got to give credit where credit is due, and I found this answer here: Windows 8 app - MediaElement not playing ".wmv" files

Related

Use of progress indicator, throws a warning and nothing happens

I'm trying to use a card according to the material design example. I copied the code
<materialDesign:Card x:Name="Progreso"
Padding="4"
UniformCornerRadius="14" Grid.ColumnSpan="3" Visibility="Hidden">
<ProgressBar
IsIndeterminate="True"
Style="{StaticResource MaterialDesignCircularProgressBar}"
Value="50" />
</materialDesign:Card>
And I insert it into a grid, because I want the grid to stall until I bring a file to my pc. So I put that covering all the grid (expanded) and then set the visibility to hidden.
In my code, I did something like this:
Progreso.Visibility = Visibility.Visible;
...
Progreso.Visibility = Visibility.Hidden;
(note: probably I will use an asyncronic method later, but I just want to make it work first).
of course, nothing happens, and I get this warning on the console:
System.Windows.Media.Animation Warning: 6 : Unable to perform action
because the specified Storyboard was never applied to this object for
interactive control.; Action='Remove';
Storyboard='System.Windows.Media.Animation.Storyboard';
Storyboard.HashCode='41234998';
Storyboard.Type='System.Windows.Media.Animation.Storyboard';
TargetElement='System.Windows.Controls.ProgressBar Minimum:0
Maximum:100 Value:50'; TargetElement.HashCode='27773061';
TargetElement.Type='System.Windows.Controls.ProgressBar'
So I think I need to do something else, but after looking at the demo, couldn't figure what else to do.
Is this the rigth aproach? or I have to do something else to make it work?

VS 2013 Windows Store .. Media Element

I'm making a windows store app and i'm trying to add a sound to the button for when you click it. I have my coding done, error free, but the sound does not play.
Any help is appreciated.
XAML
<Button x:Name="Explore" HorizontalAlignment="Left" Height="163" Margin="692,461,0,0" VerticalAlignment="Top" Width="546" BorderThickness="0" Click="Explore_Click"/>
<MediaElement x:Name="suprise" Source="Assets/suprise.mp3" AutoPlay="False" Visibility="Collapsed" HorizontalAlignment="Left" Height="147" Margin="108,285,0,0" VerticalAlignment="Top" Width="533" RenderTransformOrigin="0.5,0.5"/>
xaml.cs
private void Explore_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(Explore));
suprise.Play();
}
The MediaElement needs to be in the visual tree to play and will stop when it is removed. Since Explore_Click navigates away before surprise has played, surprise isn't able to play its sound.
You have a few options:
Let surprise finish before calling Frame.Navigate. The app can handle surprise's MediaEnded event and navigate there.
Put surprise on the Explore page and play it when that page is reached
Use a global MediaElement in a page outside of the Frame containing the app's normal pages. This will let the MediaElement stay in the visual tree even as the app switches pages beneath it. This is generally needed if you want to play a consistent soundtrack during the app, but not so much for special effects. I discuss this method in more detail in my blog entry Frame of reference: keeping the music playing across pages

Memory Leak: MVVM and photos on a LongListSelector (WP8)

I'm trying to bind some (HD) photos to a LongListSelector as you can see here:
<phone:LongListSelector
Name="Photos"
LayoutMode="Grid"
ItemsSource="{Binding Items}"
GridCellSize="225, 225"
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<Grid>
<Image Name="Photo"
Source="{Binding Source}"
</Grid>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
foreach (string item in resultList)
{
u = new Uri(item, UriKind.RelativeOrAbsolute);
this.Items.Add(new DataItemViewModel() { Source = u});
}
});
but everytime I go back to the main page and click to start this all over again (with new/different photos) the ApplicationPeakMemoryUsage just keeps increasing until the app terminates itself...
I'm sorry if it's a basic question but I'm a newbie in C#.
Any hints?
(Maybe a way to dispose the LongListSelector or the whole page when the user hits the back button)
Thank You.
Last time I had this problem I used the IDipose pattern. The problem I had was when using third party dll's, the CLR was not cleaning the objects from the dll.
After I implemented the IDispose pattern and whenever I used that specific object, I put it within the 'using' statement which ensured that it was disposed of at the end of the 'using' statement's scope. More information on the using statement: http://www.dotnetperls.com/using
To make me realise this in the first place I debugged my code and watched Task Manager. Make a breakpoint at the start of the code, and open up task manager and click on the Processes tab.
After certain points where you think the problem may lie, watch where the memory usage increases a lot.
Get back to me when you have done this.
Hope it helps, get back to me if nothing works :)

Windows Phone 8 XAML app - Clickable Rectangle object

I'm in need of making a rectangle clickable, at which it will run a function that animates it and does some stuff. I've tried to browse Microsoft's API, but I don't find anything and I'm going crazy because of this. This will be the last time I touch XAML, but I really need to know how to get this to work.
<Grid Background=Transparent>
<Grid same same>
<Rectangle MouseLeftButtonDown="moveClick" x:Name="red"
Fill="Red" Height="125" Width="125" Stroke="Pink"
StrokeThickness="10" Margin="106,196,225,348"
/>
</Grid>
</Grid>
This is one of my rectangles and I have a function called moveClick in the .xaml.cs file that should be called. In that function there is some code firing up an animation that will target this rectangles. Since I have a lot of rectangles I want to animate I am changing the target depending on which one is pressed. Problem is, the MouseEvent isn't happening. I have googled for hours but Microsoft's help is useless. I don't know what to do.
I can't really post more code than this because then I'd have to rewrite it all over due to my PC I'm programming on has no internet connection. THis is my laptop and I'm going through my phone because my normal internet is down. My desktop has no wifi.
SO, can anybody who has had experience with Windows apps tell me what the reason could be? Is it because I'm in a grid? I saw somewhere that it has to have a transparent background. It is. I'm so clueless because there's nothing to go on because wherever I look, I find something irrelevant or dead ends.
EDIT: Just to clarify, the animation works. I temporarily set it to run by pressing a button used for something else. And it works. It just doesn't work when touching the Rectangles.
EDIT TWO: I'm just using the template, and just added stuff under the ContentPanel as they call it.
An alternative/lazy approach is this:
<Button Click="moveClick" BorderThickness="0" Background="Transparent">
<Rectangle x:Name="red"
Fill="Red" Height="125" Width="125" Stroke="Pink"
StrokeThickness="10" Margin="94,184,213,336"
/>
<Button>
In the click handler you can get the inner rectangle with the recursive function grabbed from this question: How to get children of a WPF container by type?
public static T GetChildOfType<T>(this DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
The rectangle it self works fine here. MouseLeftButtonDown get invoked. It is more likely that the way you place it that matter. Can't guess without looking more XAML code.
Wild guess for workarounds, try with Tap event too and explicitly set IsHitTestVisible="True" :
......
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<Rectangle MouseLeftButtonDown="moveClick" x:Name="red"
Fill="Red" Height="125" Width="125" Stroke="Pink"
StrokeThickness="10" Margin="106,196,225,348"
Tap="red_Tap" IsHitTestVisible="True"
/>
</StackPanel>
</Grid>
......
Both event get invoked when I tap the rectangle with this setting. And when IsHitTestVisible set to false, both event doesn't get invoked, just as I expect.

Windows phone 8 slow text input in TextBox or PhoneTextBox

I have some page with TextBox or PhoneTextBox (from toolkit): Part of xaml code.
I animate scrollviewer (opacity and XProperty), befor I set datacotext for textbox.
<ScrollViewer x:Name="ContentScroller"
Visibility="Collapsed"
Margin="35,0,35,0">
<ScrollViewer.RenderTransform>
<TranslateTransform />
</ScrollViewer.RenderTransform>
<Grid x:Name="ContentGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="CreationgDate"
Text="{Binding CreationDate, StringFormat='Created: {0:dd.MM.yyyy HH:mm}'}"
Style="{StaticResource CreationDateTextStyle}"
Grid.Row="0"/>
<toolkit:PhoneTextBox x:Name="BodyData"
InputScope="Chat"
Text="{Binding Body, UpdateSourceTrigger=Explicit}"
LostFocus="BodyData_LostFocus"
TextWrapping="Wrap"
AcceptsReturn="True"
Grid.Row="1">
</toolkit:PhoneTextBox>
</Grid>
</ScrollViewer>
I update DataSource in event LostFocus:
// this I set datacontex
private async void Item_Click(object sender, RoutedEventArgs e)
{
PageHeader.DataContext = CreationgDate.DataContext = BodyData.DataContext = activeItem;
await AnimateChangePage();
}
private void BodyData_LostFocus(object sender, RoutedEventArgs e)
{
BindingExpression be = NoteBodyData.GetBindingExpression(PhoneTextBox.TextProperty);
be.UpdateSource();
}
TROUBLE: When text in textbox has 400-500 chars and more, then text input in textbox very slow, and keyboard have a lag response.
I test app in real device (not emulator), other app with same functionality (from app store) work fine without lag and slow input.
Help me with this thing please.
And sorry for my lang (not english) :) .
Following our comment discussion, this is the best answer I can give:
Run the app on your phone in debug mode.
Either straight away, or when the issue occurs, set a breakpoint in the set statement on the body property(above if property=value). When the breakpoint is hit, use the call stack to work out what is causing the update and the watch window to see the current value. You may find something is trying to update it repeatedly.
If there is anything else updating the body, there are subscribed events, or viewmodel events being fired that relate to the body, stick breakpoints on them and see if they are firing excessively.
Failing that, Stick breakpoints everywhere. For example, it may be losing focus for some reason, and triggering that event more than it should be. It could also be something else rending in the background.
All that fails, try not binding the textbox and going WinForms style of set the value and then get it back later. Remove all unnecessary events. You can then build it back up and identify the cause. If it is slow without a binding and attached events, then I really would be out of ideas.
Generally, i have found this sort of thing relates to events firing that I didn't expect. I see you are checking the incoming value is different, which will stop the dreaded MVVM property loop, but without seeing the rest of the application, its hard to narrow the issue down further.

Categories