按住按钮按下循环

时间:2016-03-26 15:37:07

标签: c# wpf

我有一个使用MediaElement的WPF应用程序。 我想循环播放视频的某个部分。我有一个StartTimeEndTime变量用于循环目的。我尝试DispatcherTimer用于循环目的,但它对于小于1秒的循环来说太慢了。所以我尝试了简单的while循环,如下所示。

while (true)
{
     if(!buttonPressed)
     {
          while (mePlayer.Position < loop.EndTime) ; //go till end of loop
          mePlayer.Position = loop.StartTime; //after reaching end of loop  start again
     }
}

使用上面的代码,甚至0.5秒的视频循环正常但是 上述方法的问题是,一旦它进入无限循环,它就无法检测按钮按下,因此我无法停止循环。所以我的问题是如何在while循环中检测按钮按下,以便我可以停止循环视频并继续执行其他任务?

1 个答案:

答案 0 :(得分:1)

我很惊讶您无法获得有关视频播放进度的任何信息。但是你可以通过组合TaskDispatcher(因为跨线程)来解决这个问题,而不会阻止用户界面,如下所示。

<强> MainWindow.xaml.cs

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private CancellationTokenSource _tokenSource;
    private double _start;
    private double _stop;

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        media.LoadedBehavior = MediaState.Manual;
        Start = 0;

        media.MediaOpened += (sender, args) =>
        {
            Stop = (int)media.NaturalDuration.TimeSpan.TotalSeconds;
            SetEndPosition();
        };
        media.Source = new Uri("video.wmv", UriKind.Relative);
        media.Play();
    }

    private async void SetEndPosition()
    {
        _tokenSource?.Cancel();
        _tokenSource = new CancellationTokenSource();
        var token = _tokenSource.Token;

        await Task.Run(() =>
        {
            if (token.IsCancellationRequested)
                return;

            while (!token.IsCancellationRequested)
            {
                Dispatcher.Invoke(() =>
                {
                    double position = media.Position.TotalSeconds;
                    if (position >= Stop)
                        SetStartPosition();
                });
                Thread.Sleep(100);
            }
        }, token);
    }

    private void SetStartPosition()
    {
        media.Position = TimeSpan.FromSeconds(Start);
    }

    public double Start
    {
        get { return _start; }
        set { _start = value; OnPropertyChanged(); SetStartPosition(); }
    }

    public double Stop
    {
        get { return _stop; }
        set { _stop = value; OnPropertyChanged(); }
    }

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

<强> MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" 
        Height="422" 
        Width="450">
<Grid Margin="10">
    <Grid.RowDefinitions>
        <RowDefinition Height="340" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <MediaElement Grid.Row="0" Grid.ColumnSpan="2" Margin="0,0,0,10" x:Name="media" />
    <TextBox Grid.Row="1" Grid.Column="0" Text="{Binding Start}"></TextBox>
    <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Stop}"></TextBox>
</Grid>

enter image description here