Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 滑块在更改轨迹NAudio后不工作_C#_Wpf_Mvvm_Slider_Naudio - Fatal编程技术网

C# 滑块在更改轨迹NAudio后不工作

C# 滑块在更改轨迹NAudio后不工作,c#,wpf,mvvm,slider,naudio,C#,Wpf,Mvvm,Slider,Naudio,我有滑块作为音轨时间线的轨迹条。使用NAudion从网络播放音轨。所有代码都使用NAudio WPF示例。我只更改了辅助功能修饰符。第一次开始播放第一首曲目时一切正常。但如果我更改为下一首曲目,滑块仍处于开始位置。并且仅当我单击暂停然后播放时才更改 要完全理解: public class AudioControlVM : ViewModelBase, IDisposable { private AudioModel _currentSong; publi

我有滑块作为音轨时间线的轨迹条。使用NAudion从网络播放音轨。所有代码都使用NAudio WPF示例。我只更改了辅助功能修饰符。第一次开始播放第一首曲目时一切正常。但如果我更改为下一首曲目,滑块仍处于开始位置。并且仅当我单击暂停然后播放时才更改

要完全理解:

public class AudioControlVM : ViewModelBase, IDisposable
    {
        private AudioModel _currentSong;

        public AudioModel CurrentSong { get { return _currentSong; } set { _currentSong = value; RaisePropertyChanged("CurrentSong"); } }

        private string inputPath, songName;
        private string defaultDecompressionFormat;
        public IWavePlayer wavePlayer { get; set; }
        private WaveStream reader;
        public RelayCommand PlayCommand { get; set; }
        public RelayCommand PauseCommand { get; set; }
        public RelayCommand StopCommand { get; set; }
        public DispatcherTimer timer = new DispatcherTimer();
        private double sliderPosition;
        private readonly ObservableCollection<string> inputPathHistory;
        private string lastPlayed;

        public AudioControlVM()
        {
            inputPathHistory = new ObservableCollection<string>();
            PlayCommand = new RelayCommand(() => Play());
            PauseCommand = new RelayCommand(() => Pause());
            StopCommand = new RelayCommand(Stop, () => !IsStopped);
            timer.Interval = TimeSpan.FromMilliseconds(500);
            timer.Tick += TimerOnTick;
        }

        public bool IsPlaying => wavePlayer != null && wavePlayer.PlaybackState == PlaybackState.Playing;

        public bool IsStopped => wavePlayer == null || wavePlayer.PlaybackState == PlaybackState.Stopped;


        public IEnumerable<string> InputPathHistory => inputPathHistory;

        const double SliderMax = 10.0;

        private void TimerOnTick(object sender, EventArgs eventArgs)
        {
            if (reader != null)
            {
                sliderPosition = reader.Position * SliderMax / reader.Length;
                RaisePropertyChanged("SliderPosition");
            }
        }

        public double SliderPosition
        {
            get => sliderPosition;
            set
            {
                if (sliderPosition != value)
                {
                    sliderPosition = value;
                    if (reader != null)
                    {
                        var pos = (long)(reader.Length * sliderPosition / SliderMax);
                        reader.Position = pos; // media foundation will worry about block align for us
                    }
                    RaisePropertyChanged("SliderPosition");
                }
            }
        }

        private bool TryOpenInputFile(string file)
        {
            bool isValid = false;
            try
            {
                using (var tempReader = new MediaFoundationReader(file))
                {
                    DefaultDecompressionFormat = tempReader.WaveFormat.ToString();
                    InputPath = file;
                    isValid = true;
                }
            }
            catch (Exception e)
            {

            }
            return isValid;
        }

        public string DefaultDecompressionFormat
        {
            get => defaultDecompressionFormat;
            set
            {
                defaultDecompressionFormat = value;
                RaisePropertyChanged("DefaultDecompressionFormat");
            }
        }

        public string SongName { get => songName; set
            {
                songName = value;
                RaisePropertyChanged("SongName");
            } }

        public string InputPath
        {
            get => inputPath;
            set
            {
                if (inputPath != value)
                {
                    inputPath = value;
                    AddToHistory(value);
                    RaisePropertyChanged("InputPath");
                }
            }
        }

        private void AddToHistory(string value)
        {
            if (!inputPathHistory.Contains(value))
            {
                inputPathHistory.Add(value);
            }
        }

        public void Stop()
        {
            if (wavePlayer != null)
            {
                wavePlayer.Stop();
            }
        }

        public void Pause()
        {
            if (wavePlayer != null)
            {
                wavePlayer.Pause();
                RaisePropertyChanged("IsPlaying");
                RaisePropertyChanged("IsStopped");
            }
        }

        public void Play()
        {
            if (String.IsNullOrEmpty(InputPath))
            {

                return;
            }
            if (wavePlayer == null)
            {
                CreatePlayer();
            }
            if (lastPlayed != inputPath && reader != null)
            {
                reader.Dispose();
                reader = null;
            }
            if (reader == null)
            {
                reader = new MediaFoundationReader(inputPath);
                lastPlayed = inputPath;
                wavePlayer.Init(reader);
            }
            wavePlayer.Play();
            RaisePropertyChanged("IsPlaying");
            RaisePropertyChanged("IsStopped");
            timer.Start();
        }

        private void CreatePlayer()
        {
            wavePlayer = new WaveOutEvent();
            wavePlayer.PlaybackStopped += WavePlayerOnPlaybackStopped;
            RaisePropertyChanged("wavePlayer");
        }

        private void WavePlayerOnPlaybackStopped(object sender, StoppedEventArgs stoppedEventArgs)
        {

            if (reader != null)
            {
                SliderPosition = 0;
                //reader.Position = 0;
                timer.Stop();
            }
            if (stoppedEventArgs.Exception != null)
            {

            }
            RaisePropertyChanged("IsPlaying");
            RaisePropertyChanged("IsStopped");
        }

        public void PlayFromUrl(string url, string songname)
        {
            Stop();
            inputPath = url;
            SongName = songname;
            Play();
        }

        public void Dispose()
        {
            wavePlayer?.Dispose();
            reader?.Dispose();
        }
    }
    <Grid>
        <StackPanel Orientation="Horizontal">
        <Button Content="Play" Command="{Binding PlayCommand}" VerticalAlignment="Center" Width="75" />
        <Button Content="Pause" Command="{Binding PauseCommand}" VerticalAlignment="Center" Width="75" />
        <Button Content="Stop" Command="{Binding PlayCommand}" VerticalAlignment="Center" Width="75" />

        <Slider VerticalAlignment="Center" Value="{Binding SliderPosition, Mode=TwoWay}" Maximum="10" Width="400" />
            <TextBlock Text="{Binding SongName, FallbackValue=Test}" Foreground="White"/>
        </StackPanel>
    </Grid>
</UserControl>
public class AudioModel
{
    public string Artist { get; set; }
    public string SongName { get; set; }
    public int Duration { get; set; }
    public string URL { get; set; }

    public RelayCommand PlayThisAudioCommand
    {
        get;
        private set;
    }

    public AudioModel()
    {
        PlayThisAudioCommand = new RelayCommand(() => PlayThis());
    }

    private void PlayThis()
    {
        if (URL != null)
        {
            TestVM.AudioConrol.PlayFromUrl(URL, SongName);
        }
        else;
    }
}
第一个轨迹-滑块工作并移动

在开始处切换到下一个轨迹滑块,并且不移动。但按暂停键后开始移动,然后播放。它立即移动到此时播放的位置,并继续正常操作。接下来的每一条轨道也是如此

用于PlayerUserControl的虚拟机代码:

public class AudioControlVM : ViewModelBase, IDisposable
    {
        private AudioModel _currentSong;

        public AudioModel CurrentSong { get { return _currentSong; } set { _currentSong = value; RaisePropertyChanged("CurrentSong"); } }

        private string inputPath, songName;
        private string defaultDecompressionFormat;
        public IWavePlayer wavePlayer { get; set; }
        private WaveStream reader;
        public RelayCommand PlayCommand { get; set; }
        public RelayCommand PauseCommand { get; set; }
        public RelayCommand StopCommand { get; set; }
        public DispatcherTimer timer = new DispatcherTimer();
        private double sliderPosition;
        private readonly ObservableCollection<string> inputPathHistory;
        private string lastPlayed;

        public AudioControlVM()
        {
            inputPathHistory = new ObservableCollection<string>();
            PlayCommand = new RelayCommand(() => Play());
            PauseCommand = new RelayCommand(() => Pause());
            StopCommand = new RelayCommand(Stop, () => !IsStopped);
            timer.Interval = TimeSpan.FromMilliseconds(500);
            timer.Tick += TimerOnTick;
        }

        public bool IsPlaying => wavePlayer != null && wavePlayer.PlaybackState == PlaybackState.Playing;

        public bool IsStopped => wavePlayer == null || wavePlayer.PlaybackState == PlaybackState.Stopped;


        public IEnumerable<string> InputPathHistory => inputPathHistory;

        const double SliderMax = 10.0;

        private void TimerOnTick(object sender, EventArgs eventArgs)
        {
            if (reader != null)
            {
                sliderPosition = reader.Position * SliderMax / reader.Length;
                RaisePropertyChanged("SliderPosition");
            }
        }

        public double SliderPosition
        {
            get => sliderPosition;
            set
            {
                if (sliderPosition != value)
                {
                    sliderPosition = value;
                    if (reader != null)
                    {
                        var pos = (long)(reader.Length * sliderPosition / SliderMax);
                        reader.Position = pos; // media foundation will worry about block align for us
                    }
                    RaisePropertyChanged("SliderPosition");
                }
            }
        }

        private bool TryOpenInputFile(string file)
        {
            bool isValid = false;
            try
            {
                using (var tempReader = new MediaFoundationReader(file))
                {
                    DefaultDecompressionFormat = tempReader.WaveFormat.ToString();
                    InputPath = file;
                    isValid = true;
                }
            }
            catch (Exception e)
            {

            }
            return isValid;
        }

        public string DefaultDecompressionFormat
        {
            get => defaultDecompressionFormat;
            set
            {
                defaultDecompressionFormat = value;
                RaisePropertyChanged("DefaultDecompressionFormat");
            }
        }

        public string SongName { get => songName; set
            {
                songName = value;
                RaisePropertyChanged("SongName");
            } }

        public string InputPath
        {
            get => inputPath;
            set
            {
                if (inputPath != value)
                {
                    inputPath = value;
                    AddToHistory(value);
                    RaisePropertyChanged("InputPath");
                }
            }
        }

        private void AddToHistory(string value)
        {
            if (!inputPathHistory.Contains(value))
            {
                inputPathHistory.Add(value);
            }
        }

        public void Stop()
        {
            if (wavePlayer != null)
            {
                wavePlayer.Stop();
            }
        }

        public void Pause()
        {
            if (wavePlayer != null)
            {
                wavePlayer.Pause();
                RaisePropertyChanged("IsPlaying");
                RaisePropertyChanged("IsStopped");
            }
        }

        public void Play()
        {
            if (String.IsNullOrEmpty(InputPath))
            {

                return;
            }
            if (wavePlayer == null)
            {
                CreatePlayer();
            }
            if (lastPlayed != inputPath && reader != null)
            {
                reader.Dispose();
                reader = null;
            }
            if (reader == null)
            {
                reader = new MediaFoundationReader(inputPath);
                lastPlayed = inputPath;
                wavePlayer.Init(reader);
            }
            wavePlayer.Play();
            RaisePropertyChanged("IsPlaying");
            RaisePropertyChanged("IsStopped");
            timer.Start();
        }

        private void CreatePlayer()
        {
            wavePlayer = new WaveOutEvent();
            wavePlayer.PlaybackStopped += WavePlayerOnPlaybackStopped;
            RaisePropertyChanged("wavePlayer");
        }

        private void WavePlayerOnPlaybackStopped(object sender, StoppedEventArgs stoppedEventArgs)
        {

            if (reader != null)
            {
                SliderPosition = 0;
                //reader.Position = 0;
                timer.Stop();
            }
            if (stoppedEventArgs.Exception != null)
            {

            }
            RaisePropertyChanged("IsPlaying");
            RaisePropertyChanged("IsStopped");
        }

        public void PlayFromUrl(string url, string songname)
        {
            Stop();
            inputPath = url;
            SongName = songname;
            Play();
        }

        public void Dispose()
        {
            wavePlayer?.Dispose();
            reader?.Dispose();
        }
    }
    <Grid>
        <StackPanel Orientation="Horizontal">
        <Button Content="Play" Command="{Binding PlayCommand}" VerticalAlignment="Center" Width="75" />
        <Button Content="Pause" Command="{Binding PauseCommand}" VerticalAlignment="Center" Width="75" />
        <Button Content="Stop" Command="{Binding PlayCommand}" VerticalAlignment="Center" Width="75" />

        <Slider VerticalAlignment="Center" Value="{Binding SliderPosition, Mode=TwoWay}" Maximum="10" Width="400" />
            <TextBlock Text="{Binding SongName, FallbackValue=Test}" Foreground="White"/>
        </StackPanel>
    </Grid>
</UserControl>
public class AudioModel
{
    public string Artist { get; set; }
    public string SongName { get; set; }
    public int Duration { get; set; }
    public string URL { get; set; }

    public RelayCommand PlayThisAudioCommand
    {
        get;
        private set;
    }

    public AudioModel()
    {
        PlayThisAudioCommand = new RelayCommand(() => PlayThis());
    }

    private void PlayThis()
    {
        if (URL != null)
        {
            TestVM.AudioConrol.PlayFromUrl(URL, SongName);
        }
        else;
    }
}

看起来您的计时器可能存在多线程问题。事件的顺序似乎是:

第一轨道
  • PlayFromUrl()调用Play(),Play()启动文件播放,启动计时器
  • 滑块按预期更新
  • 第二轨道
  • 调用PlayFromUrl()时,请执行以下操作:
  • 调用Stop()(停止wavePlayer,并停止计时器)
  • 调用Play()(启动wavePlayer,启动计时器)
  • 然后将引发wavePlayer.PlaybackStopped事件(由于您先前调用wavePlayer.Stop()),该事件调用WavePlayerOnPlaybackStopped(),该事件将停止计时器
  • 这里重要的一点是调用Play()和wavePlayerPlaybackstopped()的顺序。当wavePlayer在另一个线程上引发PlaybackStopped事件时,事件很可能按上述顺序发生

    简言之,WavePlayerOnPlaybackStopped()在
    Play()启动后停止计时器,这就是滑块没有更新的原因。按暂停然后播放将重新启动计时器,这就是滑块在暂停后开始更新的原因

    您可以通过临时注释WavePlayerPlayBackstopped()中的代码来测试这一点,这应该可以解决问题-尽管当轨迹到达终点或停止时,滑块不会重置为零

    注意:调用wavePlayer.Stop()和引发wavePlayer.PlaybackStopped事件之间延迟的原因是nAudio使用专用线程处理播放。调用Stop()时,它必须在实际停止之前完成当前音频缓冲区的处理-在大多数情况下,这将导致几毫秒的延迟


    您可以在WaveOutEvent的
    DoPlayback
    方法中看到这一点:

    看起来您的计时器可能存在多线程问题。事件的顺序似乎是:

    第一轨道
  • PlayFromUrl()调用Play(),Play()启动文件播放,启动计时器
  • 滑块按预期更新
  • 第二轨道
  • 调用PlayFromUrl()时,请执行以下操作:
  • 调用Stop()(停止wavePlayer,并停止计时器)
  • 调用Play()(启动wavePlayer,启动计时器)
  • 然后将引发wavePlayer.PlaybackStopped事件(由于您先前调用wavePlayer.Stop()),该事件调用WavePlayerOnPlaybackStopped(),该事件将停止计时器
  • 这里重要的一点是调用Play()和wavePlayerPlaybackstopped()的顺序。当wavePlayer在另一个线程上引发PlaybackStopped事件时,事件很可能按上述顺序发生

    简言之,WavePlayerOnPlaybackStopped()在
    Play()启动后停止计时器,这就是滑块没有更新的原因。按暂停然后播放将重新启动计时器,这就是滑块在暂停后开始更新的原因

    您可以通过临时注释WavePlayerPlayBackstopped()中的代码来测试这一点,这应该可以解决问题-尽管当轨迹到达终点或停止时,滑块不会重置为零

    注意:调用wavePlayer.Stop()和引发wavePlayer.PlaybackStopped事件之间延迟的原因是nAudio使用专用线程处理播放。调用Stop()时,它必须在实际停止之前完成当前音频缓冲区的处理-在大多数情况下,这将导致几毫秒的延迟


    您可以在WaveOutEvent的
    DoPlayback
    方法中看到这一点:谢谢!现在一切都好了!刚刚删除了WavePlayerPlaybackstopped()谢谢!现在一切都好了!刚刚删除了WavePlayerPlaybackstopped()