Windows Phone 8.1 Custom Media Player - windows-phone-8
Good Day,
I am creating an app in which Media Player is needed. I tried using AreTransportControlsEnabled but it is a bit laggy which is I dont want. On my windows phone I have an app "Files"<-(An Application in Windows Phone 8.1) I use it to play one of my video and I saw its Video Player. I am thinking if I can achieve this kind of Player. Any suggestion how to achieve this Player?
picture: http://s22.postimg.org/plu0oqxv5/wp_ss_20150329_0002.png
I tried making a custom controls, but when on Fullscreen the controls doesnt shows up. Is there an api or something to do this?
Question Answered
My Custom MediaPlayer
Main Page.xalm
<Page
x:Class="MediaPlayer.MainPage"
IsTabStop="false"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MediaPlayer"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Loaded="MainPage_Loaded">
<Page.Resources>
<Style x:Name="transportStyle" TargetType="Button">
<Setter Property="Height" Value="40" />
<Setter Property="Width" Value="75" />
<Setter Property="FontSize" Value="11" />
</Style>
<Thickness x:Key="PhoneBorderThickness">2.5</Thickness>
<FontFamily x:Key="PhoneFontFamilyNormal">Segoe WP</FontFamily>
<FontWeight x:Key="PhoneButtonFontWeight">Semibold</FontWeight>
<x:Double x:Key="TextStyleLargeFontSize">18.14</x:Double>
<x:Double x:Key="PhoneButtonMinHeight">0</x:Double>
<x:Double x:Key="PhoneButtonMinWidth">0</x:Double>
<Thickness x:Key="PhoneTouchTargetOverhang">0,0</Thickness>
<SolidColorBrush x:Key="ButtonDisabledBackgroundThemeBrush" Color="Transparent"/>
<Style x:Key="RoundButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{ThemeResource PhoneForegroundBrush}"/>
<Setter Property="Foreground" Value="{ThemeResource PhoneForegroundBrush}"/>
<Setter Property="BorderThickness" Value="{ThemeResource PhoneBorderThickness}"/>
<Setter Property="FontFamily" Value="{ThemeResource PhoneFontFamilyNormal}"/>
<Setter Property="FontWeight" Value="{ThemeResource PhoneButtonFontWeight}"/>
<Setter Property="FontSize" Value="{ThemeResource TextStyleLargeFontSize}"/>
<Setter Property="Padding" Value="9.5,0"/>
<Setter Property="MinHeight" Value="{ThemeResource PhoneButtonMinHeight}"/>
<Setter Property="MinWidth" Value="{ThemeResource PhoneButtonMinWidth}"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Path Stretch="Uniform"
RenderTransformOrigin="0.5,0.5"
Margin="2,6,2,2"
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Data="{Binding Path=Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"></Path>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="Grid" Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition From="Pressed" To="PointerOver">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="Grid"/>
</Storyboard>
</VisualTransition>
<VisualTransition From="PointerOver" To="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="Grid"/>
</Storyboard>
</VisualTransition>
<VisualTransition From="Pressed" To="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="Grid"/>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="PointerOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonPressedForegroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonPressedBackgroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonDisabledForegroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonDisabledBorderThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Border">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonDisabledBackgroundThemeBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="{ThemeResource PhoneTouchTargetOverhang}" Height="{Binding Path=Height, RelativeSource={RelativeSource Mode=TemplatedParent}}" Width="{Binding Path=Width, RelativeSource={RelativeSource Mode=TemplatedParent}}" CornerRadius="72">
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<!--<RowDefinition Height="150"/>-->
</Grid.RowDefinitions>
<ContentControl x:Name="videoContainer"
KeyUp="VideoContainer_KeyUp"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Grid.Row="0" >
<MediaElement Name="videoMediaElement"
Source="Media/video1.mp4"
MediaOpened="videoElement_MediaOpened"
MediaEnded="videoMediaElement_MediaEnded"
MediaFailed="videoMediaElement_MediaFailed"
CurrentStateChanged="videoMediaElement_CurrentStateChanged"
PosterSource="Media/Video1_Poster.png" PointerPressed="videoMediaElement_PointerPressed" />
</ContentControl>
<!-- Transport Controls -->
<StackPanel Name="TransportControlsPanel"
Grid.Row="0" VerticalAlignment="Bottom" Background="#CC000000" >
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,15,0,0">
<Button HorizontalAlignment="Left" Click="btnReverse_Click" VerticalAlignment="Top" Style="{StaticResource RoundButtonStyle}" Height="72" Width="72" Content="M13.862404,0L17.667,3.8059161 10.879305,10.593651 17.6241,17.568752 13.861103,21.333 3.1840002,10.678149z M0,0L3.0719999,0 3.0719999,21.032 0,21.032z" Padding="20,5" Margin="20,0" BorderBrush="White" Background="#FFE6E6E6"/>
<Button x:Name="Play1" HorizontalAlignment="Left" Click="btnPlay_Click" VerticalAlignment="Top" Style="{StaticResource RoundButtonStyle}" Height="72" Width="72" Content="M27.270001,0L44.310001,0 44.310001,48.643002 27.270001,48.643002z M0,0L17.040001,0 17.040001,48.643002 0,48.643002z" Padding="20,10" Margin="20,0" BorderBrush="White" Background="#FFE6E6E6"/>
<Button HorizontalAlignment="Left" Click="btnForward_Click" VerticalAlignment="Top" Style="{StaticResource RoundButtonStyle}" Height="72" Width="72" Content="M14.595,0L17.668,0 17.668,21.032 14.595,21.032z M3.8059254,0L14.484001,10.67815 3.8059254,21.333 0.04431057,17.568752 6.7875929,10.593651 0,3.8059165z" Padding="20,5" Margin="20,0" BorderBrush="White" Background="#FFE6E6E6"/>
<Button HorizontalAlignment="Left" Click="btnFullScreenToggle_Click" VerticalAlignment="Top" Style="{StaticResource RoundButtonStyle}" Height="72" Width="72" Content="M0,2.3629998L11.63953,2.3629998 9.1447105,4.8564929 2.4934592,4.8564929 2.4934592,14.710437 12.712251,14.710437 12.712251,8.4683789 15.206,5.9748863 15.206,17.204 0,17.204z M11.741774,0L17.591398,0 17.591999,5.8514608 15.648591,3.9075235 7.7964079,11.759001 5.8289994,9.7914637 13.681183,1.9400271z" Padding="13,10,10,15" Margin="20,0" BorderBrush="White" Background="#FFE6E6E6"/>
</StackPanel>
<Slider Name="timelineSlider" HorizontalContentAlignment="Stretch" Margin="10,20,10,0"/>
<TextBlock x:Name="TextBlock1" Text="00:0 / 00:0" FontSize="18" Margin="20,0,20,40" Foreground="White"/>
</StackPanel>
</Grid>
MainPage.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
// You should use the MediaElement.IsFullWindow property instead
// to enable and disable full window rendering.
private bool _isFullscreenToggle = false;
public bool IsFullscreen
{
get { return _isFullscreenToggle; }
set { _isFullscreenToggle = value; }
}
private Size _previousVideoContainerSize = new Size();
private async void FullscreenToggle()
{
this.IsFullscreen = !this.IsFullscreen;
if (this.IsFullscreen)
{
//TransportControlsPanel.Visibility = Visibility.Collapsed;
await Windows.UI.ViewManagement.StatusBar.GetForCurrentView().HideAsync();
DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape | DisplayOrientations.LandscapeFlipped;
_previousVideoContainerSize.Width = videoContainer.ActualWidth;
_previousVideoContainerSize.Height = videoContainer.ActualHeight;
videoContainer.Width = Window.Current.Bounds.Width;
videoContainer.Height = Window.Current.Bounds.Height;
videoMediaElement.Width = Window.Current.Bounds.Width;
videoMediaElement.Height = Window.Current.Bounds.Height;
// Trigger the Visual State Manager
//VisualStateManager.GoToState(this, "Landscape", false);
}
else
{
//TransportControlsPanel.Visibility = Visibility.Visible;
await Windows.UI.ViewManagement.StatusBar.GetForCurrentView().ShowAsync();
DisplayInformation.AutoRotationPreferences = DisplayOrientations.None;
videoContainer.Width = _previousVideoContainerSize.Width;
videoContainer.Height = _previousVideoContainerSize.Height;
videoMediaElement.Width = _previousVideoContainerSize.Width;
videoMediaElement.Height = _previousVideoContainerSize.Height;
// Trigger the Visual State Manager
//VisualStateManager.GoToState(this, "Portrait",false);
}
}
private void btnFullScreenToggle_Click(object sender, RoutedEventArgs e)
{
FullscreenToggle();
}
private void VideoContainer_KeyUp(object sender, KeyRoutedEventArgs e)
{
if (IsFullscreen && e.Key == Windows.System.VirtualKey.Escape)
{
FullscreenToggle();
}
e.Handled = true;
}
private void btnPlay_Click(object sender, RoutedEventArgs e)
{
if (videoMediaElement.DefaultPlaybackRate != 1)
{
videoMediaElement.DefaultPlaybackRate = 1.0;
}
if (videoMediaElement.CurrentState == MediaElementState.Playing)
{
videoMediaElement.Pause();
Play1.Content = "M0,0L384.885,191.965 769.768,383.928 384.885,576.035 0,768 0,383.928z"; // Play
Play1.Padding = new Thickness(19, 5, 12, 5);
}
else if (videoMediaElement.CurrentState == MediaElementState.Paused)
{
videoMediaElement.Play();
Play1.Content = "M27.270001,0L44.310001,0 44.310001,48.643002 27.270001,48.643002z M0,0L17.040001,0 17.040001,48.643002 0,48.643002z";
Play1.Padding = new Thickness(20, 10, 20, 10);
}
}
DispatcherTimer timer = new DispatcherTimer();
public void Start_timer()
{
timer.Tick += timer_Tick;
timer.Interval = new TimeSpan(00, 0, 5);
bool enabled = timer.IsEnabled;
timer.Start();
}
void timer_Tick(object sender, object e)
{
//function to execute
if (TransportControlsPanel.Visibility == Windows.UI.Xaml.Visibility.Visible)
{
TransportControlsPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
timer.Stop();
}
private void btnPause_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.Pause();
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.Stop();
}
private void btnForward_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.DefaultPlaybackRate = 2.0;
videoMediaElement.Play();
}
private void btnReverse_Click(object sender, RoutedEventArgs e)
{
double Int1 = videoMediaElement.Position.TotalSeconds - 10;
if (Int1 > 0)
{
videoMediaElement.Position = TimeSpan.FromSeconds(videoMediaElement.Position.TotalSeconds - 10);
videoMediaElement.Play();
}
else
{
videoMediaElement.Position = TimeSpan.FromSeconds(0);
videoMediaElement.Play();
}
}
private void btnVolumeDown_Click(object sender, RoutedEventArgs e)
{
if (videoMediaElement.IsMuted)
{
videoMediaElement.IsMuted = false;
}
if (videoMediaElement.Volume < 1)
{
videoMediaElement.Volume += .1;
}
}
private void btnMute_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.IsMuted = !videoMediaElement.IsMuted;
}
private void btnVolumeUp_Click(object sender, RoutedEventArgs e)
{
if (videoMediaElement.IsMuted)
{
videoMediaElement.IsMuted = false;
}
if (videoMediaElement.Volume > 0)
{
videoMediaElement.Volume -= .1;
}
}
private void cbAudioTracks_SelectionChanged(
object sender, SelectionChangedEventArgs e)
{
//videoMediaElement.AudioStreamIndex = cbAudioTracks.SelectedIndex;
}
private void PopulateAudioTracks(
MediaElement media, ComboBox audioSelection)
{
if (media.AudioStreamCount > 0)
{
for (int index = 0; index < media.AudioStreamCount; index++)
{
ComboBoxItem track = new ComboBoxItem();
track.Content = media.GetAudioStreamLanguage(index);
audioSelection.Items.Add(track);
}
}
}
private async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
timelineSlider.ValueChanged += timelineSlider_ValueChanged;
PointerEventHandler pointerpressedhandler = new PointerEventHandler(slider_PointerEntered);
timelineSlider.AddHandler(Control.PointerPressedEvent, pointerpressedhandler, true);
PointerEventHandler pointerreleasedhandler = new PointerEventHandler(slider_PointerCaptureLost);
timelineSlider.AddHandler(Control.PointerCaptureLostEvent, pointerreleasedhandler, true);
}
void videoElement_MediaOpened(object sender, RoutedEventArgs e)
{
double absvalue = (int)Math.Round(
videoMediaElement.NaturalDuration.TimeSpan.TotalSeconds,
MidpointRounding.AwayFromZero);
timelineSlider.Maximum = absvalue;
timelineSlider.StepFrequency =
SliderFrequency(videoMediaElement.NaturalDuration.TimeSpan);
SetupTimer();
// Helper method to populate the combobox with audio tracks.
//PopulateAudioTracks(videoMediaElement, cbAudioTracks);
}
private bool _sliderpressed = false;
void slider_PointerEntered(object sender, PointerRoutedEventArgs e)
{
_sliderpressed = true;
}
void slider_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
{
videoMediaElement.Position = TimeSpan.FromSeconds(timelineSlider.Value);
_sliderpressed = false;
}
void timelineSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
if (!_sliderpressed)
{
videoMediaElement.Position = TimeSpan.FromSeconds(e.NewValue);
}
}
void videoMediaElement_CurrentStateChanged(object sender, RoutedEventArgs e)
{
if (videoMediaElement.CurrentState == MediaElementState.Playing)
{
Play1.Content = "M27.270001,0L44.310001,0 44.310001,48.643002 27.270001,48.643002z M0,0L17.040001,0 17.040001,48.643002 0,48.643002z";
Play1.Padding = new Thickness(20, 10, 20, 10);
if (_sliderpressed)
{
_timer.Stop();
}
else
{
_timer.Start();
}
}
if (videoMediaElement.CurrentState == MediaElementState.Paused)
{
Play1.Content = "M0,0L384.885,191.965 769.768,383.928 384.885,576.035 0,768 0,383.928z"; // Play
Play1.Padding = new Thickness(19, 5, 12, 5);
_timer.Stop();
}
if (videoMediaElement.CurrentState == MediaElementState.Stopped)
{
_timer.Stop();
timelineSlider.Value = 0;
}
}
void videoMediaElement_MediaEnded(object sender, RoutedEventArgs e)
{
StopTimer();
timelineSlider.Value = 0.0;
}
private void videoMediaElement_MediaFailed(object sender, ExceptionRoutedEventArgs e)
{
// get HRESULT from event args
string hr = GetHresultFromErrorMessage(e);
// Handle media failed event appropriately
}
private string GetHresultFromErrorMessage(ExceptionRoutedEventArgs e)
{
String hr = String.Empty;
String token = "HRESULT - ";
const int hrLength = 10; // eg "0xFFFFFFFF"
int tokenPos = e.ErrorMessage.IndexOf(token, StringComparison.Ordinal);
if (tokenPos != -1)
{
hr = e.ErrorMessage.Substring(tokenPos + token.Length, hrLength);
}
return hr;
}
private DispatcherTimer _timer;
private void SetupTimer()
{
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(1);
StartTimer();
}
private void _timer_Tick(object sender, object e)
{
if (!_sliderpressed)
{
timelineSlider.Value = videoMediaElement.Position.TotalSeconds;
TimeSpan TS = new TimeSpan(videoMediaElement.Position.Hours, videoMediaElement.Position.Minutes, videoMediaElement.Position.Seconds);
TimeSpan TS1 = new TimeSpan(videoMediaElement.NaturalDuration.TimeSpan.Hours, videoMediaElement.NaturalDuration.TimeSpan.Minutes, videoMediaElement.NaturalDuration.TimeSpan.Seconds);
TextBlock1.Text = TS.Duration().ToString("c") + " / " + TS1.Duration().ToString("c");
}
}
private void StartTimer()
{
_timer.Tick += _timer_Tick;
_timer.Start();
}
private void StopTimer()
{
_timer.Stop();
_timer.Tick -= _timer_Tick;
}
private double SliderFrequency(TimeSpan timevalue)
{
double stepfrequency = -1;
double absvalue = (int)Math.Round(
timevalue.TotalSeconds, MidpointRounding.AwayFromZero);
stepfrequency = (int)(Math.Round(absvalue / 100));
if (timevalue.TotalMinutes >= 10 && timevalue.TotalMinutes < 30)
{
stepfrequency = 10;
}
else if (timevalue.TotalMinutes >= 30 && timevalue.TotalMinutes < 60)
{
stepfrequency = 30;
}
else if (timevalue.TotalHours >= 1)
{
stepfrequency = 60;
}
if (stepfrequency == 0) stepfrequency += 1;
if (stepfrequency == 1)
{
stepfrequency = absvalue / 100;
}
return stepfrequency;
}
private void videoMediaElement_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (TransportControlsPanel.Visibility == Windows.UI.Xaml.Visibility.Visible)
{
TransportControlsPanel.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
timer.Stop();
}
else
{
TransportControlsPanel.Visibility = Windows.UI.Xaml.Visibility.Visible;
Start_timer();
}
}
}
Next time try to give you code, show what you did this way it's easier to help.
Did you saw the page on msdn that explain how to do a custom media player control ?
How to create custom media transport controls (XAML)
You mentioned AreTransportControlsEnabled and I don't think it's laggy, remember that if you try on the simulator, it's a VM that runs Windows Phone so if you don't have a very powerfull computer you can see some lags that you won't see on a Nokia 930 for example.
But if you still want to make it custom, I think you can start from the code given by Msdn.
MainPage.xaml
<Page
x:Class="MediaPlayerQuickStart.MainPage"
IsTabStop="false"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MediaPlayerQuickStart"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Loaded="MainPage_Loaded">
<Page.Resources>
<Style x:Name="transportStyle" TargetType="Button">
<Setter Property="Height" Value="40" />
<Setter Property="Width" Value="75" />
<Setter Property="FontSize" Value="11" />
</Style>
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<ContentControl x:Name="videoContainer"
KeyUp="VideoContainer_KeyUp"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Height="400" Grid.Row="0" >
<MediaElement Name="videoMediaElement"
Source="Media/video1.mp4"
MediaOpened="videoElement_MediaOpened"
MediaEnded="videoMediaElement_MediaEnded"
MediaFailed="videoMediaElement_MediaFailed"
CurrentStateChanged="videoMediaElement_CurrentStateChanged"
PosterSource="Media/Video1_Poster.png"
AutoPlay="False" />
</ContentControl>
<!-- Transport Controls -->
<StackPanel Name="TransportControlsPanel"
HorizontalAlignment="Center"
Grid.Row="1" >
<Slider Name="timelineSlider" Margin="10,0" Width="200"/>
<StackPanel Orientation="Horizontal">
<Button Name="btnPlay" Click="btnPlay_Click"
Style="{StaticResource transportStyle}" Content="Play" />
<Button Name="btnPause" Click="btnPause_Click"
Style="{StaticResource transportStyle}" Content="Pause" />
<Button Name="btnStop" Click="btnStop_Click"
Style="{StaticResource transportStyle}" Content="Stop" />
<Button Name="btnReverse" Click="btnReverse_Click"
Style="{StaticResource transportStyle}" Content="Rewind" />
<Button Name="btnForward" Click="btnForward_Click"
Style="{StaticResource transportStyle}" Content="Forward" />
<Button Name="btnMute" Click="btnMute_Click"
Style="{StaticResource transportStyle}" Content="Mute" />
<Button Name="btnFullScreenToggle" Click="btnFullScreenToggle_Click"
Style="{StaticResource transportStyle}" Content="Full" />
<ComboBox Name="cbAudioTracks"
SelectionChanged="cbAudioTracks_SelectionChanged"
Width="75" />
<Button Name="btnVolumeUp" Click="btnVolumeUp_Click"
Style="{StaticResource transportStyle}" Content="-" />
<Button Name="btnVolumeDown" Click="btnVolumeDown_Click"
Style="{StaticResource transportStyle}" Content="+" />
<TextBlock Name="txtVolume" FontSize="14"
Text="{Binding Volume, ElementName=videoMediaElement}"
VerticalAlignment="Center" HorizontalAlignment="Right" />
</StackPanel>
</StackPanel>
</Grid>
</Page>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
// You should use the MediaElement.IsFullWindow property instead
// to enable and disable full window rendering.
private bool _isFullscreenToggle = false;
public bool IsFullscreen
{
get { return _isFullscreenToggle; }
set { _isFullscreenToggle = value; }
}
private Size _previousVideoContainerSize = new Size();
private void FullscreenToggle()
{
this.IsFullscreen = !this.IsFullscreen;
if (this.IsFullscreen)
{
TransportControlsPanel.Visibility = Visibility.Collapsed;
_previousVideoContainerSize.Width = videoContainer.ActualWidth;
_previousVideoContainerSize.Height = videoContainer.ActualHeight;
videoContainer.Width = Window.Current.Bounds.Width;
videoContainer.Height = Window.Current.Bounds.Height;
videoMediaElement.Width = Window.Current.Bounds.Width;
videoMediaElement.Height = Window.Current.Bounds.Height;
}
else
{
TransportControlsPanel.Visibility = Visibility.Visible;
videoContainer.Width = _previousVideoContainerSize.Width;
videoContainer.Height = _previousVideoContainerSize.Height;
videoMediaElement.Width = _previousVideoContainerSize.Width;
videoMediaElement.Height = _previousVideoContainerSize.Height;
}
}
private void btnFullScreenToggle_Click(object sender, RoutedEventArgs e)
{
FullscreenToggle();
}
private void VideoContainer_KeyUp(object sender, KeyRoutedEventArgs e)
{
if (IsFullscreen && e.Key == Windows.System.VirtualKey.Escape)
{
FullscreenToggle();
}
e.Handled = true;
}
private void btnPlay_Click(object sender, RoutedEventArgs e)
{
if (videoMediaElement.DefaultPlaybackRate != 1)
{
videoMediaElement.DefaultPlaybackRate = 1.0;
}
videoMediaElement.Play();
}
private void btnPause_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.Pause();
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.Stop();
}
private void btnForward_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.DefaultPlaybackRate = 2.0;
videoMediaElement.Play();
}
private void btnReverse_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.DefaultPlaybackRate = -2;
videoMediaElement.Play();;
}
private void btnVolumeDown_Click(object sender, RoutedEventArgs e)
{
if (videoMediaElement.IsMuted)
{
videoMediaElement.IsMuted = false;
}
if (videoMediaElement.Volume < 1)
{
videoMediaElement.Volume += .1;
}
}
private void btnMute_Click(object sender, RoutedEventArgs e)
{
videoMediaElement.IsMuted = !videoMediaElement.IsMuted;
}
private void btnVolumeUp_Click(object sender, RoutedEventArgs e)
{
if (videoMediaElement.IsMuted)
{
videoMediaElement.IsMuted = false;
}
if (videoMediaElement.Volume > 0)
{
videoMediaElement.Volume -= .1;
}
}
private void cbAudioTracks_SelectionChanged(
object sender, SelectionChangedEventArgs e)
{
videoMediaElement.AudioStreamIndex = cbAudioTracks.SelectedIndex;
}
private void PopulateAudioTracks(
MediaElement media, ComboBox audioSelection)
{
if (media.AudioStreamCount > 0)
{
for (int index = 0; index < media.AudioStreamCount; index++)
{
ComboBoxItem track = new ComboBoxItem();
track.Content = media.GetAudioStreamLanguage(index);
audioSelection.Items.Add(track);
}
}
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
timelineSlider.ValueChanged += timelineSlider_ValueChanged;
PointerEventHandler pointerpressedhandler = new PointerEventHandler(slider_PointerEntered);
timelineSlider.AddHandler(Control.PointerPressedEvent, pointerpressedhandler, true);
PointerEventHandler pointerreleasedhandler = new PointerEventHandler(slider_PointerCaptureLost);
timelineSlider.AddHandler(Control.PointerCaptureLostEvent, pointerreleasedhandler, true);
}
void videoElement_MediaOpened(object sender, RoutedEventArgs e)
{
double absvalue = (int)Math.Round(
videoMediaElement.NaturalDuration.TimeSpan.TotalSeconds,
MidpointRounding.AwayFromZero);
timelineSlider.Maximum = absvalue;
timelineSlider.StepFrequency =
SliderFrequency(videoMediaElement.NaturalDuration.TimeSpan);
SetupTimer();
// Helper method to populate the combobox with audio tracks.
PopulateAudioTracks(videoMediaElement, cbAudioTracks);
}
private bool _sliderpressed = false;
void slider_PointerEntered(object sender, PointerRoutedEventArgs e)
{
_sliderpressed = true;
}
void slider_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
{
videoMediaElement.Position = TimeSpan.FromSeconds(timelineSlider.Value);
_sliderpressed = false;
}
void timelineSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
if (!_sliderpressed)
{
videoMediaElement.Position = TimeSpan.FromSeconds(e.NewValue);
}
}
void videoMediaElement_CurrentStateChanged(object sender, RoutedEventArgs e)
{
if (videoMediaElement.CurrentState == MediaElementState.Playing)
{
if (_sliderpressed)
{
_timer.Stop();
}
else
{
_timer.Start();
}
}
if (videoMediaElement.CurrentState == MediaElementState.Paused)
{
_timer.Stop();
}
if (videoMediaElement.CurrentState == MediaElementState.Stopped)
{
_timer.Stop();
timelineSlider.Value = 0;
}
}
void videoMediaElement_MediaEnded(object sender, RoutedEventArgs e)
{
StopTimer();
timelineSlider.Value = 0.0;
}
private void videoMediaElement_MediaFailed(object sender, ExceptionRoutedEventArgs e)
{
// get HRESULT from event args
string hr = GetHresultFromErrorMessage(e);
// Handle media failed event appropriately
}
private string GetHresultFromErrorMessage(ExceptionRoutedEventArgs e)
{
String hr = String.Empty;
String token = "HRESULT - ";
const int hrLength = 10; // eg "0xFFFFFFFF"
int tokenPos = e.ErrorMessage.IndexOf(token, StringComparison.Ordinal);
if (tokenPos != -1)
{
hr = e.ErrorMessage.Substring(tokenPos + token.Length, hrLength);
}
return hr;
}
private DispatcherTimer _timer;
private void SetupTimer()
{
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(timelineSlider.StepFrequency);
StartTimer();
}
private void _timer_Tick(object sender, object e)
{
if (!_sliderpressed)
{
timelineSlider.Value = videoMediaElement.Position.TotalSeconds;
}
}
private void StartTimer()
{
_timer.Tick += _timer_Tick;
_timer.Start();
}
private void StopTimer()
{
_timer.Stop();
_timer.Tick -= _timer_Tick;
}
private double SliderFrequency(TimeSpan timevalue)
{
double stepfrequency = -1;
double absvalue = (int)Math.Round(
timevalue.TotalSeconds, MidpointRounding.AwayFromZero);
stepfrequency = (int)(Math.Round(absvalue / 100));
if (timevalue.TotalMinutes >= 10 && timevalue.TotalMinutes < 30)
{
stepfrequency = 10;
}
else if (timevalue.TotalMinutes >= 30 && timevalue.TotalMinutes < 60)
{
stepfrequency = 30;
}
else if (timevalue.TotalHours >= 1)
{
stepfrequency = 60;
}
if (stepfrequency == 0) stepfrequency += 1;
if (stepfrequency == 1)
{
stepfrequency = absvalue / 100;
}
return stepfrequency;
}
}
If you want to change the look of the buttons you can use AppBarButton instead of normal buttons (give them the round windows8 like look)
To change the behavior for fullscreen, look at FullscreenToggle(). In this example they collapse the StackPanel with the controls but you don't have to and can implement your own logic.
Related
How to add ListView to player from PlayerFramework (windows app)?
I added a button to player from PlayerFramework, when click that button, a ListView appear for select video quality. But I dont know how to implement ItemClicked event to handle when user click a item in ListView. Anyone can help me? My code: Entertainment.xaml <AppBarButton x:Name="QualityButton" Grid.Column="3" Width="30" Height="30" Margin="8,0,8,0" Icon="Setting" Style="{TemplateBinding TransportBarButtonStyle}" Visibility="Visible"> <AppBarButton.Flyout> <Flyout> <ListView Name="listView" IsItemClickEnabled="True" ItemsSource="{Binding List}"> <ListView.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}" /> </DataTemplate> </ListView.ItemTemplate> </ListView> </Flyout> </AppBarButton.Flyout> </AppBarButton> CustomInteractiveViewModel.cs public class CustomInteractiveViewModel : InteractiveViewModel { public CustomInteractiveViewModel(List<string> list, MediaPlayer player) : base(player) { List = list; } public List<string> List { get; set; } } MainPage.cs protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); var list = new List<string> { "360p", "480p", "720p" }; player.InteractiveViewModel = new CustomInteractiveViewModel(list, player); player.Source = new Uri(Video, UriKind.RelativeOrAbsolute); } MainPage.xaml <Page x:Class="testPlayer.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="using:testPlayer" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mmppf="using:Microsoft.PlayerFramework" xmlns:webvtt="using:Microsoft.PlayerFramework.WebVTT" mc:Ignorable="d"> <Page.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Themes/Entertainment.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Page.Resources> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <mmppf:MediaPlayer Name="player" /> </Grid> </Page>
It is not supported to binding event like ItemClick or SelectionChanged in ResourceDictionary, a simple method is to create the code behind of this ResourceDictionary, but to maintain the MVVM pattern integrity, it's better to register a Attached property, and bind events to this attached property. You can change your code in Entertainment.xaml like this: <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="using:Microsoft.PlayerFramework.Controls" xmlns:local="using:Microsoft.PlayerFramework"> ... <AppBarButton x:Name="QualityButton" Grid.Column="3" Width="30" Height="30" Margin="8,0,8,0" Icon="Setting" Style="{TemplateBinding TransportBarButtonStyle}" Visibility="Visible"> <AppBarButton.Flyout> <Flyout> <ListView Name="listView" IsItemClickEnabled="True" ItemsSource="{Binding List}" controls:CustomInteractiveViewModel.ItemClickCommand="{Binding ItemClickedCommand}"> <ListView.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}" /> </DataTemplate> </ListView.ItemTemplate> </ListView> </Flyout> </AppBarButton.Flyout> </AppBarButton> ... </ResourceDictionary> and the code in CustomInteractiveViewModel.cs: public class CustomInteractiveViewModel : InteractiveViewModel { public CustomInteractiveViewModel(List<string> list, MediaPlayer player, DelegateCommand<string> itemclickedcommand) : base(player) { List = list; ItemClickedCommand = itemclickedcommand; } public List<string> List { get; set; } public DelegateCommand<string> ItemClickedCommand { get; set; } public static DependencyProperty ItemClickCommandProperty = DependencyProperty.RegisterAttached("ItemClickCommand", typeof(ICommand), typeof(CustomInteractiveViewModel), new PropertyMetadata(null, OnItemClickCommandChanged)); public static void SetItemClickCommand(DependencyObject target, ICommand value) { target.SetValue(ItemClickCommandProperty, value); } public static ICommand GetItemClickCommand(DependencyObject target) { return (ICommand)target.GetValue(ItemClickCommandProperty); } private static void OnItemClickCommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) { var element = target as ListViewBase; if (element != null) { if ((e.NewValue != null) && (e.OldValue == null)) { element.ItemClick += OnItemClick; } else if ((e.NewValue == null) && (e.OldValue != null)) { element.ItemClick -= OnItemClick; } } } private static void OnItemClick(object sender, ItemClickEventArgs e) { GetItemClickCommand(sender as ListViewBase).Execute(e.ClickedItem); } } Finally in your MainPage.cs: protected override void OnNavigatedTo(NavigationEventArgs e) { base.OnNavigatedTo(e); var list = new List<string> { "360p", "480p", "720p" }; var ItemClickedCommand = new DelegateCommand<string>(ItemClicked); player.InteractiveViewModel = new CustomInteractiveViewModel(list, player, ItemClickedCommand); } public void ItemClicked(string item) { //TODO: } And the DelegateCommand<T> class is like this: public class DelegateCommand<T> : ICommand { private readonly Action<T> _execute; private readonly Func<T, bool> _canExecute; public event EventHandler CanExecuteChanged; public DelegateCommand(Action<T> execute, Func<T, bool> canexecute = null) { if (execute == null) throw new ArgumentNullException(nameof(execute)); _execute = execute; _canExecute = canexecute ?? (e => true); } public bool CanExecute(object p) { try { return _canExecute(ConvertParameterValue(p)); } catch { return false; } } public void Execute(object p) { if (!this.CanExecute(p)) return; _execute(ConvertParameterValue(p)); } private static T ConvertParameterValue(object parameter) { parameter = parameter is T ? parameter : Convert.ChangeType(parameter, typeof(T)); return (T)parameter; } public void RaiseCanExecuteChanged() { CanExecuteChanged?.Invoke(this, EventArgs.Empty); } }
How to get guesture from one canvas to set on another canvas programatically in windows phone 8 app
i'm creating simple canvas application which is to get the signature from canvas which is named as "ContentPanelCanvas" which is from Grid named as "pop-up" and to set that signature from "Pop-up" and to set on canvas named as "maincanvas". If you know Please help me to resolve this issue how to get the canvas context and set it to blank canvas.Here is the code i used. In Xaml: <Grid x:Name="ContentPanel"> <Grid.RowDefinitions> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"></ColumnDefinition> </Grid.ColumnDefinitions> <Grid Grid.Column="0"> <Canvas Name="maincanvas"> </Canvas> </Grid> <Grid Name="Popup" Visibility="Collapsed" Grid.Row="0" Width="480" Height="300" Background="Black"> <Grid.RowDefinitions> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid Grid.Row="0"> <Canvas Name="ContentPanelCanvas" Background="Beige"> </Canvas> </Grid> <Grid Grid.Row="1" HorizontalAlignment="Center"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"></ColumnDefinition> <ColumnDefinition Width="*"></ColumnDefinition> </Grid.ColumnDefinitions> <Button Grid.Column="0" x:Name="btnOK" Content="OK" Tap="btnOK_Tap"/> <Button Grid.Column="1" x:Name="btnCancel" Content="Clear" Tap="btnCancel_Tap"/> </Grid> </Grid> </Grid> Here is the .CS file: private Point currentPoint; private Point oldPoint; Line line; public SingleImage() { InitializeComponent(); this.ContentPanelCanvas.MouseMove += new MouseEventHandler(ContentPanelCanvas_MouseMove); this.ContentPanelCanvas.MouseLeftButtonDown += new MouseButtonEventHandler(ContentPanelCanvas_MouseLeftButtonDown); } void ContentPanelCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { currentPoint = e.GetPosition(ContentPanelCanvas); oldPoint = currentPoint; } void ContentPanelCanvas_MouseMove(object sender, MouseEventArgs e) { currentPoint = e.GetPosition(this.ContentPanelCanvas); line = new Line() { X1 = currentPoint.X, Y1 = currentPoint.Y, X2 = oldPoint.X, Y2 = oldPoint.Y }; line.Stroke = new SolidColorBrush(Colors.Purple); line.StrokeThickness = 3; this.ContentPanelCanvas.Children.Add(line); oldPoint = currentPoint; } private void Button_Tap(object sender, System.Windows.Input.GestureEventArgs e) { Popup.Visibility = Visibility.Visible; ContentPanelCanvas.Children.Clear(); } private void btnOK_Tap(object sender, System.Windows.Input.GestureEventArgs e) { Popup.Visibility = Visibility.Collapsed; // Here i want to set signature to main canvas how to pass signature from one canvas to another?// } private void btnCancel_Tap(object sender, System.Windows.Input.GestureEventArgs e) { ContentPanelCanvas.Children.Clear(); }
private void btnOK_Tap(object sender, System.Windows.Input.GestureEventArgs e) { Popup.Visibility = Visibility.Collapsed; int k = ContentPanelCanvas.Children.Count; for (int i = 0; i < k; i++) { line =(System.Windows.Shapes.Line) ContentPanelCanvas.Children[0]; line.StrokeThickness = 3; ContentPanelCanvas.Children.RemoveAt(0); maincanvas.Children.Add(line); } }
Using FlipView to create TabControl in Metro Apps
i'm currently creating a Metro Style Application and want to use the FlipView control to work like the tab control in WPF and winforms, please can any one help me ?
You would put FlipViewItems in the FlipView the same way you'd put TabItems in a TabControl. To add tabs - you could have a StackPanel with TextRadioButtonStyled RadioButtons that have their check states synchronized with the FlipView selection state. Alternatively you could have a heavily styled ListView for the headers bar.
i solved it by editing the flipviewitem template and making its view like the wanted tab page view. Then i added a button on the top of every item to activate it.
We don't have Tab Control in WP8.1 but we can customize using FlipView. Flip View has a property selected index so we can set which view we want. Create a xaml page, for example MainPage.xaml For Tab Header <Border BorderThickness="0,0,0,1" BorderBrush="White" > <Grid Grid.Row="0" Background="Black" x:Name="navigateHead" > <TextBlock x:Name="appbarSports" Text="Sports" Tapped="appbarSports_Tapped" TextAlignment="Center" Width="80" Margin="0,34,320,7" /> <TextBlock x:Name="appbarCars" Text="Cars" Tapped="appbarCars_Tapped" Margin="160,34,160,7" TextAlignment="Center" /> <TextBlock x:Name="appbarHomes" Text="Homes" Tapped="appbarHomes_Tapped" Margin="80,34,240,7" TextAlignment="Center" /> <Image x:Name="imgLine0" Source="ms-appx:///Images/white.png" Width="80" Height="3" Stretch="Fill" Margin="0,55,320,1" ></Image> <Image x:Name="imgLine1" Source="ms-appx:///Images/white.png" Width="80" Height="3" Stretch="Fill" Margin="81,55,239,1" Visibility="Collapsed" /> <Image x:Name="imgLine2" Source="ms-appx:///Images/white.png" Width="80" Height="3" Stretch="Fill" Margin="162,55,158,1" Visibility="Collapsed" /> </Grid> </Border> For Flip view XAML code is <Grid Grid.Row="1" > <FlipView x:Name="flipControl" SelectionChanged="flipControl_SelectionChanged" > <FlipViewItem > <ListView x:Name="listViewForSports" > <ListView.ItemTemplate> <DataTemplate> <Image Stretch="Fill" Source="{Binding SportsImage}"></Image> </DataTemplate> </ListView.ItemTemplate> </ListView> </FlipViewItem> <FlipViewItem > <ListView x:Name="listViewForHomes"> <ListView.ItemTemplate> <DataTemplate> <Image Source="{Binding HomesImage}" Stretch="Fill"></Image> </DataTemplate> </ListView.ItemTemplate> </ListView> </FlipViewItem> <FlipViewItem > <ListView x:Name="listViewForCars"> <ListView.ItemTemplate> <DataTemplate> <Image Source="{Binding CarsImage}" Stretch="Fill"></Image> </DataTemplate> </ListView.ItemTemplate> </ListView> </FlipViewItem> </FlipView> </Grid>` and write in code behind file MainPage.xaml.cs Just initialize these globally: public sealed partial class MainPage : Page { List<Sports> listOfSports; List<Cars> listOfCars; List<Homes> listOfHomes; public MainPage() { this.InitializeComponent(); this.NavigationCacheMode = NavigationCacheMode.Required; } bind data to the FlipView control when page is initialized protected override void OnNavigatedTo(NavigationEventArgs e) { flipControl.SelectedIndex = 0; // TODO: Prepare page for display here. // TODO: If your application contains multiple pages, ensure that you are // handling the hardware Back button by registering for the // Windows.Phone.UI.Input.HardwareButtons.BackPressed event. // If you are using the NavigationHelper provided by some templates, // this event is handled for you. GetData(); } This method will bind public void GetData() { listOfSports = new List<Sports>(); for (int i = 1; i < 9; i++) { listOfSports.Add(new Sports() { SportsImage = #"ms-appx:///Images/Sports/image" + i.ToString() + ".jpg" }); } listViewForSports.ItemsSource = listOfSports; listOfCars = new List<Cars>(); for (int i = 1; i < 14; i++) { listOfCars.Add(new Cars() { CarsImage = #"ms-appx:///Images/Cars/image" + i.ToString() + ".jpg" }); } listViewForCars.ItemsSource = listOfCars; listOfHomes = new List<Homes>(); for (int i = 1; i < 9; i++) { listOfHomes.Add(new Homes() { HomesImage = #"ms-appx:///Images/Homes/image" + i.ToString() + ".jpg" }); } listViewForHomes.ItemsSource = listOfHomes; } public class Cars { public string CarsImage { get; set; } } public class Sports { public string SportsImage { get; set; } } public class Homes { public string HomesImage { get; set; } }` I did with tap event to navigation withing flip view` private void appbarSports_Tapped(object sender, TappedRoutedEventArgs e) { // TextBlock a = sender as TextBlock; // imgLine0.Margin = new Thickness(a.Margin.Left, 55, a.Margin.Right, 1); flipControl.SelectedIndex = 0; method(0); } private void appbarCars_Tapped(object sender, TappedRoutedEventArgs e) { // TextBlock a = sender as TextBlock; //imgLine0.Margin = new Thickness(a.Margin.Left, 55, a.Margin.Right, 1); flipControl.SelectedIndex = 2; method(2); } private void appbarHomes_Tapped(object sender, TappedRoutedEventArgs e) { // TextBlock a = sender as TextBlock; // imgLine0.Margin = new Thickness(a.Margin.Left, 55, a.Margin.Right, 1); flipControl.SelectedIndex = 1; method(1); } I also used for when the user flips so I used FlipView.SelectionChanged event private void flipControl_SelectionChanged(object sender, SelectionChangedEventArgs e) { FlipView viewControl = sender as FlipView; int a = viewControl.SelectedIndex; method(a); } This method() is help full for changing imageLine position public void method(int a) { if (imgLine0 != null) { switch (a) { case 0: imgLine0.Visibility = Visibility.Visible; imgLine1.Visibility = Visibility.Collapsed; imgLine2.Visibility = Visibility.Collapsed; break; case 1: imgLine0.Visibility = Visibility.Collapsed; imgLine1.Visibility = Visibility.Visible; imgLine2.Visibility = Visibility.Collapsed; break; case 2: imgLine0.Visibility = Visibility.Collapsed; imgLine1.Visibility = Visibility.Collapsed; imgLine2.Visibility = Visibility.Visible; break; } } }
WinRT Custom control: OnApplyTemplate seems to be invoked not in the right time
I've written a custom control which aimed at displaying a placeholder image while real image is loading. It's been written in universal app. This is the code of my control: public class DeferredImage : Control { public static readonly DependencyProperty PlaceholderSourceProperty = DependencyProperty.Register("PlaceholderSource", typeof(ImageSource), typeof(DeferredImage), new PropertyMetadata(null, OnPlaceholderSourcePropertyChanged)); public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ImageSource), typeof(DeferredImage), new PropertyMetadata(null, OnSourcePropertyChanged)); public static readonly DependencyProperty StretchProperty = DependencyProperty.Register("Stretch", typeof(Stretch), typeof(DeferredImage), new PropertyMetadata(Stretch.Uniform, OnStretchPropertyChanged)); private const string PlaceholderImageName = "PlaceholderImage"; private const string ActualImageName = "ActualImage"; private const string DefaultStateName = "DefaultState"; private const string ActualStateName = "ActualState"; private Image _placeholderImage; private Image _actualImage; public ImageSource PlaceholderSource { get { return (ImageSource)GetValue(PlaceholderSourceProperty); } set { SetValue(PlaceholderSourceProperty, value); } } public ImageSource Source { get { return (ImageSource)GetValue(SourceProperty); } set { SetValue(SourceProperty, value); } } public Stretch Stretch { get { return (Stretch)GetValue(StretchProperty); } set { SetValue(StretchProperty, value); } } public DeferredImage() { DefaultStyleKey = typeof(DeferredImage); } protected override void OnApplyTemplate() { base.OnApplyTemplate(); _placeholderImage = GetTemplateChild(PlaceholderImageName) as Image; _actualImage = GetTemplateChild(ActualImageName) as Image; if (_placeholderImage != null) { _placeholderImage.Source = PlaceholderSource; _placeholderImage.Stretch = Stretch; } if (_actualImage != null) { _actualImage.Source = Source; _actualImage.Stretch = Stretch; } } private static void OnPlaceholderSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var defferedImage = d as DeferredImage; if (defferedImage != null && defferedImage._placeholderImage != null) { defferedImage._placeholderImage.Source = (ImageSource)e.NewValue; } } private static void OnSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { var defferedImage = o as DeferredImage; if (defferedImage != null && defferedImage._actualImage != null) { var newImageSource = (ImageSource)e.NewValue; defferedImage._actualImage.Source = newImageSource; VisualStateManager.GoToState(defferedImage, newImageSource == null ? DefaultStateName : ActualStateName, false); } } private static void OnStretchPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var instance = d as DeferredImage; if (instance != null) { if (instance._placeholderImage != null) instance._placeholderImage.Stretch = (Stretch)e.NewValue; if (instance._actualImage != null) instance._actualImage.Stretch = (Stretch)e.NewValue; } } } And here is the code of the control's template: <Style TargetType="controls:DeferredImage"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="controls:DeferredImage"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="DefaultState"> <Storyboard> <DoubleAnimation Duration="0:0:0.3" To="1" Storyboard.TargetName="PlaceholderImage" Storyboard.TargetProperty="Opacity" /> <DoubleAnimation Duration="0:0:0.3" To="0" Storyboard.TargetName="ActualImage" Storyboard.TargetProperty="Opacity" /> </Storyboard> </VisualState> <VisualState x:Name="ActualState"> <Storyboard> <DoubleAnimation Duration="0:0:0.3" To="0" Storyboard.TargetName="PlaceholderImage" Storyboard.TargetProperty="Opacity" /> <DoubleAnimation Duration="0:0:0.3" To="1" Storyboard.TargetName="ActualImage" Storyboard.TargetProperty="Opacity" /> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Image Name="PlaceholderImage" Opacity="1" Canvas.ZIndex="-1" /> <Image Name="ActualImage" Opacity="0" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> At first glance this seems to work properly. But I've faced the problem: when I rotate the tablet I have OnSourcePropertyChanged handler being invoked after OnApplyTemplate method. As a consequence _actualImage field is equal to NULL inside OnSourcePropertyChanged handler and I don't have my images displayed after rotating the tablet. Does anyone know the workflow of Control's work after rotating? Where the problem might be?
The problem was solved by adding VisualStateManager.GoToState(defferedImage, newImageSource == null ? DefaultStateName : ActualStateName, false); inside the OnApplyTemplate method.
Longlist will not update at load
I am having some problems making a long list selector load my data, and i have been unable to find a solution to this problem. This is my xaml: <phone:LongListSelector x:Name="animeList" Margin="0,0,-12,0" ItemsSource="{Binding Animes}" Tap="AnimeList_OnTap"> <phone:LongListSelector.ItemTemplate> <DataTemplate> <StackPanel Margin="0,0,0,17"> <TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"> <toolkit:ContextMenuService.ContextMenu> <toolkit:ContextMenu IsZoomEnabled="false"> <toolkit:MenuItem Header="Add as favorit" Click="AddFavorite" /> </toolkit:ContextMenu> </toolkit:ContextMenuService.ContextMenu> </TextBlock> </StackPanel> </DataTemplate> </phone:LongListSelector.ItemTemplate> </phone:LongListSelector> My view model is simple: public ObservableCollection<AnimeItemViewModel> _animes { get; set; } public ObservableCollection<AnimeItemViewModel> Animes { get { return _animes; } set { if (value != _animes) { _animes = value; NotifyPropertyChanged("Animes"); } } } And how i load my data: public MainPage() { InitializeComponent(); DataContext = App.ViewModel; this.Loaded += OnLoaded; } private void OnLoaded(object sender, RoutedEventArgs routedEventArgs) { ObservableCollection<AnimeItemViewModel> _animes = new ObservableCollection<AnimeItemViewModel>(); foreach (var i in App.AnimeList.List) _animes.Add(new AnimeItemViewModel() { AId = i.AId, Name = i.Name }); App.ViewModel.Animes = _animes; } And lastly just to show that there are data in the list Update: I also have a search function, and if i enter a search text will the longlist update, but i am for some reason unable to scroll private void OnKeyDown(object sender, System.Windows.Input.KeyEventArgs e) { if (e.Key == Key.Enter) { ObservableCollection<AnimeItemViewModel> _animes = new ObservableCollection<AnimeItemViewModel>(); foreach (var i in App.AnimeList.List) if (string.IsNullOrWhiteSpace(SearchTextBox.Text) || i.Name.ToLower().Contains(SearchTextBox.Text.ToLower())) _animes.Add(new AnimeItemViewModel() { AId = i.AId, Name = i.Name }); App.ViewModel.Animes = _animes; } }
Try placing your loading code in OnNavigatedTo. As for the scrolling issue - setting a proper height to the StackPanel. Let me know if it works.