C# wpf slider实现显示进度、拖动定位、点击定位功能


前言

实现一个播放器,必然需要一个进度条,一个基本的进度条通常用于显示进度、拖动定位,也可以点击定位,在wpf通常使用slider实现,改变其Value可以显示进度,但是拖动和点击也使用Value或ValueChanged时就会产生冲突,直接死循环了,所以我们需要将这3个功能区分开来,用不同的方式去实现。


一、如何实现?

1.显示进度

显示进度直接通过Slider的Value以及Minimum和Maximum实现即可。

设置播放总时长

sd_cursorTime.Minimum = 0;
sd_cursorTime.Maximum = e.Duration;//视频总时长

更新播放进度

sd_cursorTime.Value = e.Time;//当前播放时间

2.拖动定位

slider和scrollbar一样是基于RangeBase,其内部构造是一样的,甚至style也可以共用,其内部构造可以参考《C# wpf ScrollBar自定义样式详解》。slider的滑块就是一个Thumb控件,所以我们只需要注册Thumb控件的DragStarted和DragCompleted事件以及添加一个忽略当前播放时间标识,即能实现拖动定位了。

注册事件

 <Slider x:Name="sd_cursorTime"  Thumb.DragStarted="sb_cursorTime_DragStarted"   Thumb.DragDelta="sb_cursorTime_DragDelta" Thumb.DragCompleted="sb_cursorTime_DragCompleted"   />

事件中定位

//是否忽略播放进度更新
bool _isIgnoreCursorTime = false;
private void sd_cursorTime_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{    //忽略播放进度更新,让进度条拖动不受影响。
    _isIgnoreCursorTime = true;
}
private void sb_cursorTime_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
     //拖动中实时定位。根据需求,也可以不使用。
   _play.Seek(sb_cursorTime.Value);
}
private void sd_cursorTime_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
{    
     //播放器定位
     _play.Seek(sb_cursorTime.Value);
     //还原标识,然进度条重新变化。
    _isIgnoreCursorTime = false;
}

忽略播放进度更新

if(!_isIgnoreCursorTime )
sd_cursorTime.Value = e.Time;//当前播放时间

3.点击定位

一般到了这里,会想到直接使用IsMoveToPointEnabled="True"来实现点击定位,但实际上会遇到问题,点击进度条只会触发Value改变,使用Value会和显示进度功能冲突,而且IsMoveToPointEnabled设为True之后Slider的轨道会无法响应鼠标按下弹起事件,所以使用这个属性是行不通的。我们需要做是使用Slider的MouseDown事件,在事件中进行计算进度值然后定位。
需要注意IsMoveToPointEnabled不可设为True

 <Slider x:Name="sd_cursorTime" PreviewMouseDown="sb_cursorTime_MouseDown" />
private void sd_cursorTime_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{  
    //根据鼠标点击位置的x值计算定位的Value值,下列代码是轨道宽等于slider控件宽的算法,如果情况不同情自行调整。
    var value = (e.GetPosition(sd_cursorTime).X / sd_cursorTime.ActualWidth) * (sd_cursorTime.Maximum - sd_cursorTime.Minimum);
    //播放器定位
    _play.Seek(value);
}

二、效果预览

由于完整例子代码规模略大,涉及到一个完整的播放器,不便在这里展示,如果弄一个定时器的demo又不太真实,所以这里只给出效果预览:
在这里插入图片描述


总结

以上就是今天要讲的内容,实现一个播放进度条其实主要难点在于数据响应冲突,不能共用一个事件,需要将3个功能关联的事件独立开来。曾经试过只用Value绑定和ValueChanged的实现,以及使用一个隐藏slider用来定位的方式实现,但效果都不是特别好,本文讲述则是很好的实现了功能且简单易懂。

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeOfCC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值