隐藏

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

发布:2023/3/20 0:22:45作者:管理员 来源:本站 浏览次数:695

文章目录


   前言

   一、如何实现?

       1.显示进度

       2.拖动定位

       3.点击定位

   二、效果预览

   总结


前言


实现一个播放器,必然需要一个进度条,一个基本的进度条通常用于显示进度、拖动定位,也可以点击定位,在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用来定位的方式实现,但效果都不是特别好,本文讲述则是很好的实现了功能且简单易懂。