正如标题所说,我有一个自定义滑块,声明如下:
<customControls:ThumbDragSlider IsEnabled="{Binding PlayerSourceState}"
Style="{StaticResource {x:Type Slider}}"
Value="{Binding CurrentMediaPlayer.MediaElement.Position, Mode=TwoWay, Converter={converters:SecondsToTimeSpanConverter}}"/>
还有更多属性被设置,更多事件和一些命令绑定,但我已经省略了它们,因为我已经将性能问题缩小到这个特定的行:
Value="{Binding CurrentMediaPlayer.MediaElement.Position, Mode=TwoWay, Converter={converters:SecondsToTimeSpanConverter}}"
删除它也会消除所有延迟。在我的电脑上它运行得很好,但是在没有GPU的旧机器上进行测试时,仅使用CPU,它运行不好。此滑块用于浏览MediaElement
,滞后在实际媒体文件中最为普遍,甚至是快门。
转换器声明如下:
[ValueConversion(typeof(double), typeof(TimeSpan))]
public class SecondsToTimeSpanConverter : BaseConverter, IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value is TimeSpan ts)
{
return ts;
}
return TimeSpan.FromSeconds((double)value);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return TimeSpan.FromSeconds((double)value);
}
}
自定义滑块如下:
public class ThumbDragSlider : Slider
{
public event DragStartedEventHandler DragStarted;
public event DragCompletedEventHandler DragCompleted;
public event EventHandler<MouseEventArgs> ThumbMouseEnter;
public new TimeSpan Value
{
get => TimeSpan.FromSeconds(base.Value);
set => base.Value = value.TotalSeconds;
}
public ThumbDragSlider()
{
Loaded += OnLoaded;
}
private void OnLoaded(object sender, System.Windows.RoutedEventArgs e)
{
Loaded -= OnLoaded;
var track = this.GetElementFromTemplate<Track>("PART_Track");
track.Thumb.MouseEnter += (o, args) => ThumbMouseEnter?.Invoke(o, args);
}
protected override void OnThumbDragStarted(DragStartedEventArgs e)
{
base.OnThumbDragStarted(e);
DragStarted?.Invoke(this, e);
}
protected override void OnThumbDragCompleted(DragCompletedEventArgs e)
{
base.OnThumbDragCompleted(e);
DragCompleted?.Invoke(this, e);
}
}
每隔250ms会触发一个计时器事件,以使滑块值与MediaElement
值同步,绑定无法执行此操作,因为MediaElement
没有DependencyProperty
负责对于Position
,也没有正在被解雇的INotifyPropertyChanged
事件。
System.Timers.Timer的事件处理程序:
Application.Current.Dispatcher.Invoke(() => sMovieSkipSlider.Value =
ViewModel.CurrentMediaPlayer.MediaElement.Position);
可能导致问题的原因是什么?如何解决?
答案 0 :(得分:1)
我真的不需要创建自定义滑块。我相信这可以通过使用常规滑块来实现。
您说明了以下内容:
每隔250ms会触发一个计时器事件,以使滑块值与
MediaElement
值同步,绑定无法执行此操作,因为MediaElement
没有DependencyProperty
负责对于Position
,也没有正在被解雇的INotifyPropertyChanged
事件。
然后没有必要使用绑定,您可以简单地处理滑块的MouseLeftButtonUpEvent
并以此方式设置Position
的{{1}}。
也许每250ms更新一次的计时器也可能太快,当然这取决于您的要求。就像你计划高精度地使用它一样。但是如果你只想要一个简单的玩家,那么每1秒更新一次就足够了。
以下是初始化更新滑块的计时器的示例:
MediaElement
将private TimeSpan TotalTime;
private DispatcherTimer MediaTimer;
private void CurrentMediaPlayer_MediaOpened(object sender, RoutedEventArgs e)
{
TotalTime = CurrentMediaPlayer.MediaElement.NaturalDuration.TimeSpan;
MediaTimer = new DispatcherTimer();
MediaTimer.Interval = TimeSpan.FromSeconds(1);
//If 1 second is too slow, change this to: TimeSpan.FromMilliseconds(250)
MediaTimer.Tick += new EventHandler(MediaTimer_Tick);
MediaTimer.Start();
}
private void MediaTimer_Tick(object sender, EventArgs e)
{
if (CurrentMediaPlayer.MediaElement.NaturalDuration.TimeSpan.TotalSeconds > 0)
{
if (TotalTime.TotalSeconds > 0)
{
sMovieSkipSlider.Value = CurrentMediaPlayer.MediaElement.Position.TotalSeconds /
TotalTime.TotalSeconds;
}
}
}
添加到滑块:
MouseLeftButtonUpEventHandler
以下是处理事件以更新sMovieSkipSlider.AddHandler(MouseLeftButtonUpEvent, new MouseButtonEventHandler(sMovieSkipSlider_MouseLeftButtonUp), true);
的{{1}}的示例:
Position
评论:我已经搞砸了你的一些MVVM设置,但这至少应该让你朝着正确的方向前进。您可以随时使用视图的MediaElement
属性。
答案 1 :(得分:1)
您是否尝试过设置绑定延迟?
NET_SALES
0 818817.2
1 362377.2
2 374644.6
3 518613.0
4 368510.9
5 374644.6
6 NaN
7 46382.5
8 55933.7
9 292303.4
10 382928.6
也许你必须玩不同的价值观。
答案 2 :(得分:0)
没有设置值会导致绑定触发并更新媒体播放器的位置,但是由于经过几毫秒才发生这一切,媒体播放器会稍微跳回来引起口吃?我会采取措施在同步过程中不更新媒体播放器的位置。