使用Slider实现音乐进度条,有两种思路:
1)使用数据绑定双向绑定Slider.Value与MediaElement.Position .
2) 使用Timer在适当的时间间隔间将MediaElement.Position代表的毫秒数同步到Slider.Value.
首先尝试第一种解决方案:
因为Slider.value与MediaElemen.position不能直接绑定,所以需要定义一个converter,双向绑定的Converter:
public class MyConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((TimeSpan)value).TotalMilliseconds;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int myvalue = (int)((double)value);
return new TimeSpan(0, 0, 0, 0, myvalue);
}
}
在Xmal里引入Converter定义在的命名空间:
xmlns:myns="clr-namespace:PhoneApp_PlayMedia"
MyConverter作为Grid的静态资源:
<Grid.Resources>
<myns:MyConverter x:Key="MyConverter"></myns:MyConverter>
</Grid.Resources>
将Slider的value与MediaElement的Position双向绑定并指定converter:
<Slider x:Name="MediaSlider" Value="{Binding Path=Position,ElementName=MyMedia,Mode=TwoWay,Converter={StaticResource MyConverter}}"/>
调试之后发现播放卡顿,Slider不能更新,需要点击UI元素才能使slider继续跟随音乐播放滑动,手动滑动slider之后又继续停止重绘。
再考虑使用Time更新slider加上捕获slider的valuechangedevent来更新流位置的解决方案,这个比较简单,代码如下:
private Timer sliderTimer;
// 用来表示slider的滑动是否由Timer引起
private bool flag = false;public void DisposeSliderTimer()
{
if (this.sliderTimer != null)
{
this.sliderTimer.Dispose();
this.sliderTimer = null;
}
}
public void sliderTimerCallback(object obj)
{
Dispatcher.BeginInvoke(() =>
{
flag = true;
MediaSlider.Value = MyMedia.Position.TotalMilliseconds;
});
}private void MediaSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
// flag indicate wheather the valuechanged event was raised by the timer (wheather the slider was slide by the timer).
if (flag)
{
flag = false;
return;
}
// if not,seek to the position by slider's value (indicate the slider was slide by user).
int sliderValue = (int)MediaSlider.Value;
TimeSpan ts = new TimeSpan(0, 0, 0, 0, sliderValue);
MyMedia.Position = ts;
}
// 播放private void PlayMedia_Click(object sender, RoutedEventArgs e)
{ MyMedia.Play();
// 启动Timer
sliderTimer = new Timer(sliderTimerCallback,null,0,100);
}
// 停止private void Stop_Click(object sender, RoutedEventArgs e)
{
DmonMedia.Stop();
DisposeSliderTimer();
MediaSlider.Value = 0.0;
}
// App.xmal.cs中:private void Application_Closing(object sender, ClosingEventArgs e)
{
(this.RootVisual as MainPage).DisposeSliderTimer();
}
注意定义一个flag辨别是否手动滑动slider,并在valuechanged中检查。
运行起来效果良好,可以通过slider定位音乐进度,slider还会跟随音乐播放而自动滑动,互不影响。