有一個很好的答案,但我想添加另一種在WPF中構建seekbar的方式,因爲我也在處理類似的項目。
下面是導引頭的XAML代碼:
<Slider Grid.Column="0" Minimum="0" Maximum="{Binding CurrentTrackLenght, Mode=OneWay}" Value="{Binding CurrentTrackPosition, Mode=TwoWay}" x:Name="SeekbarControl" VerticalAlignment="Center">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding TrackControlMouseDownCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseUp">
<i:InvokeCommandAction Command="{Binding TrackControlMouseUpCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</Slider>
在我們的視圖模型CurrentTrackLenght
和CurrentTrackPosition
是:
public double CurrentTrackLenght
{
get { return _currentTrackLenght; }
set
{
if (value.Equals(_currentTrackLenght)) return;
_currentTrackLenght = value;
OnPropertyChanged(nameof(CurrentTrackLenght));
}
}
public double CurrentTrackPosition
{
get { return _currentTrackPosition; }
set
{
if (value.Equals(_currentTrackPosition)) return;
_currentTrackPosition = value;
OnPropertyChanged(nameof(CurrentTrackPosition));
}
}
的想法是非常簡單的;一旦我們開始玩:
首先我們得到音頻文件的長度在幾秒鐘內,並將其分配給CurrentTrackLenght
屬性,它將被綁定到seekbar的Maximum
屬性。 然後,當我們播放音頻文件時,我們不斷更新CurrentTrackPosition
屬性,這反過來又驅動我們的seekbar的Value
屬性。
所以,當我們按下「播放」按鈕,按照我們的視圖模型的命令將運行:
private void StartPlayback(object p)
{
if (_playbackState == PlaybackState.Stopped)
{
if (CurrentTrack != null)
{
_audioPlayer.LoadFile(CurrentTrack.Filepath, CurrentVolume);
CurrentTrackLenght = _audioPlayer.GetLenghtInSeconds();
}
}
_audioPlayer.TogglePlayPause(CurrentVolume);
}
_audioPlayer
是我用來緩解播放/暫停/停止的抽象,這樣你就可以代替那些你自己的代碼。但重要的部分是:
CurrentTrackLenght = _audioPlayer.GetLenghtInSeconds();
而在AudioPlayer
爲GetLenghtInSeconds()
代碼:
public double GetLenghtInSeconds()
{
if (_audioFileReader != null)
{
return _audioFileReader.TotalTime.TotalSeconds;
}
else
{
return 0;
}
}
所以用這個,我們初始化我們的搜索條對我們開始播放每個音頻文件Maximum
值。
現在,我們需要更新我們的seekbar作爲音頻播放。
首先我們需要確定我們音頻文件的當前位置,以秒爲單位。我在這裏選擇秒,因爲我們的搜索欄Maximum
也在幾秒鐘內,所以它們將正確匹配。
要做到這一點,我們需要在AudioPlayer
下面的方法:
public double GetPositionInSeconds()
{
if (_audioFileReader != null)
{
return _audioFileReader.CurrentTime.TotalSeconds;
}
else
{
return 0;
}
}
有了這個代碼完成後,我們可以繼續我們的視圖模型。首先,我們需要在構造函數中設置一個計時器。
var timer = new System.Timers.Timer();
timer.Interval = 300;
timer.Elapsed += Timer_Elapsed;
timer.Start();
並添加Timer_Elapsed()
和UpdateSeekBar()
方法:
private void UpdateSeekBar()
{
if (_playbackState == PlaybackState.Playing)
{
CurrentTrackPosition = _audioPlayer.GetPositionInSeconds();
}
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
UpdateSeekBar();
}
有了這個工作,現在當我們播放音頻文件我們的搜索條如預期應該移動。
現在對於實際的查找部分,首先我們需要在AudioPlayer
類中使用SetPosition()
方法。
public void SetPosition(double value)
{
if (_audioFileReader != null)
{
_audioFileReader.CurrentTime = TimeSpan.FromSeconds(value);
}
}
該代碼將當前時間設置爲我們通過的值,因此有效地尋找到新的位置。
最後,我們需要4種方法來完成我們的ViewModel命令PreviewMouseDown
和PreviewMouseUp
事件。
private void TrackControlMouseDown(object p)
{
_audioPlayer.Pause();
}
private void TrackControlMouseUp(object p)
{
_audioPlayer.SetPosition(CurrentTrackPosition);
_audioPlayer.Play(NAudio.Wave.PlaybackState.Paused, CurrentVolume);
}
private bool CanTrackControlMouseDown(object p)
{
if (_playbackState == PlaybackState.Playing)
{
return true;
}
return false;
}
private bool CanTrackControlMouseUp(object p)
{
if (_playbackState == PlaybackState.Paused)
{
return true;
}
return false;
}
如果你想看到這些究竟如何實現的,你可以去我的github page,看到了完整的實現。
您是使用WinForms還是WPF? –
我正在使用Windows窗體 – GunJack