windows-store-appswin-universal-appmedia-playermediaelementwindows-8.1-universal

How to add ListView to player from PlayerFramework (windows app)?


enter image description here

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>

Solution

  • 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);
        }
    }