如何从 PlayerFramework(windows 应用程序)将 ListView 添加到播放器?

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

我从 PlayerFramework 向播放器添加了一个按钮,当单击该按钮时,会出现 select 视频质量的 ListView。
但是我不知道如何实现 ItemClicked 事件来处理当用户单击 ListView 中的项目时。谁能帮帮我?

我的代码:

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>

不支持在ResourceDictionary中绑定ItemClickSelectionChanged事件,一个简单的方法是创建这个ResourceDictionary的代码,但是保持 MVVM 模式的完整性,最好注册一个 Attached property,并将事件绑定到这个附加的 属性。

您可以像这样更改 Entertainment.xaml 中的代码:

<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>

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

终于在你的 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:
}

DelegateCommand<T> class 是这样的:

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