C# WPF中ItemTemplate内MediaElement实现无限循环播放的方法
解决方案
1. 实现无限循环播放
由于Storyboard方法无效,我们可以通过监听MediaElement的MediaEnded事件,在播放结束时重置播放位置并重新启动播放。为适配DataTemplate的场景,推荐用附加属性封装循环逻辑,避免后台代码直接操作UI元素:
创建附加属性类
public static class MediaElementHelper { public static readonly DependencyProperty LoopEnabledProperty = DependencyProperty.RegisterAttached( "LoopEnabled", typeof(bool), typeof(MediaElementHelper), new PropertyMetadata(false, OnLoopEnabledChanged)); public static bool GetLoopEnabled(DependencyObject obj) { return (bool)obj.GetValue(LoopEnabledProperty); } public static void SetLoopEnabled(DependencyObject obj, bool value) { obj.SetValue(LoopEnabledProperty, value); } private static void OnLoopEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is MediaElement mediaElement) { if ((bool)e.NewValue) { mediaElement.MediaEnded += MediaElement_MediaEnded; } else { mediaElement.MediaEnded -= MediaElement_MediaEnded; } } } private static void MediaElement_MediaEnded(object sender, RoutedEventArgs e) { if (sender is MediaElement mediaElement) { mediaElement.Position = TimeSpan.Zero; mediaElement.Play(); } } }
在DataTemplate中启用循环
修改MosaicGridStyleMP4模板,给MediaElement添加附加属性:
<DataTemplate x:Key="MosaicGridStyleMP4"> <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="10" Margin="2,2,2,2"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="60"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBlock Text="{Binding PK_SpotABS}" Width="Auto" /> <MediaElement x:Name="mePlayer" Source="{Binding Media.Source, Mode=OneWay}" Volume="0" Grid.Row="1" local:MediaElementHelper.LoopEnabled="True"/> </Grid> </Border> </DataTemplate>
2. 添加播放/停止控制按钮
为每个列表项的ViewModel添加播放、停止命令,在DataTemplate中绑定命令并传递对应的MediaElement作为参数:
列表项ViewModel示例
假设列表项ViewModel为PageItemViewModel,添加控制命令:
public class PageItemViewModel : INotifyPropertyChanged { public string PK_SpotABS { get; set; } public MediaInfo Media { get; set; } public ICommand PlayCommand { get; } public ICommand StopCommand { get; } public PageItemViewModel() { PlayCommand = new RelayCommand<MediaElement>(media => { media.Position = TimeSpan.Zero; media.Play(); }); StopCommand = new RelayCommand<MediaElement>(media => { media.Stop(); }); } // INotifyPropertyChanged接口实现代码... }
注:RelayCommand是常见的ICommand实现,可自行定义或使用MVVM框架提供的实现
修改DataTemplate添加控制按钮
在模板中新增播放/停止按钮,绑定ViewModel的命令并传入当前MediaElement:
<DataTemplate x:Key="MosaicGridStyleMP4"> <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="10" Margin="2,2,2,2"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="60"/> <RowDefinition Height="*"/> <RowDefinition Height="40"/> </Grid.RowDefinitions> <TextBlock Text="{Binding PK_SpotABS}" Width="Auto" /> <MediaElement x:Name="mePlayer" Source="{Binding Media.Source, Mode=OneWay}" Volume="0" Grid.Row="1" local:MediaElementHelper.LoopEnabled="True"/> <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center"> <Button Content="播放" Margin="5" Command="{Binding PlayCommand}" CommandParameter="{Binding ElementName=mePlayer}"/> <Button Content="停止" Margin="5" Command="{Binding StopCommand}" CommandParameter="{Binding ElementName=mePlayer}"/> </StackPanel> </Grid> </Border> </DataTemplate>
简化方案(非MVVM场景)
如果不需要严格遵循MVVM,可直接在DataTemplate中给MediaElement绑定MediaEnded事件,后台代码实现循环:
<MediaElement x:Name="mePlayer" Source="{Binding Media.Source, Mode=OneWay}" Volume="0" Grid.Row="1" MediaEnded="MePlayer_MediaEnded"/>
后台代码:
private void MePlayer_MediaEnded(object sender, RoutedEventArgs e) { if (sender is MediaElement mediaElement) { mediaElement.Position = TimeSpan.Zero; mediaElement.Play(); } }
内容的提问来源于stack exchange,提问作者HegeGabi
相关产品推荐
相关产品推荐

