現在動画再生アプリを作成しています。
MediaElementで動画の再生
Sliderでシークバーを実装しています。
また、00:10:15/00:30:00
というような感じで、TextBoxで再生中動画の総時間と現在再生中の時間を表示しています。
他にも再生ボタン等もありますが、今回の質問には関係ないので割愛します。
MediaElementの再生時間(MediaElement.Position)の取得はBindingに対応していないため、
ビヘイビアを使用して、500msのタイマーで定期的にPositionを取得するようにしています。
また、Sliderによる再生箇所の変更・ユーザー指定による指定箇所へのジャンプの機能を実装するためにもビヘイビアを使用しています。
C#
1 /// <summary> 2 /// 再生時間バインド用プロパティ 3 /// </summary> 4 public static readonly DependencyProperty MediaPositionProperty = 5 DependencyProperty.RegisterAttached( 6 "MediaPosition", 7 typeof(long), 8 typeof(MediaControlBehavior), 9 new PropertyMetadata(0L, OnMediaPositionPropertyChanged)); 10 11 /// <summary> 12 /// MediaPositionPropertyのゲッター 13 /// </summary> 14 /// <param name="target"></param> 15 /// <returns></returns> 16 public static long GetMediaPosition(DependencyObject target) 17 { 18 return (long)target.GetValue(MediaPositionProperty); 19 } 20 21 /// <summary> 22 /// MediaPositionPropertyのセッター 23 /// </summary> 24 /// <param name="target"></param> 25 /// <param name="value"></param> 26 public static void SetMediaPosition(DependencyObject target, long value) 27 { 28 target.SetValue(MediaPositionProperty, value); 29 } 30 31 /// <summary> 32 /// 再生時間変更時処理 33 /// </summary> 34 /// <param name="sender"></param> 35 /// <param name="e"></param> 36 private static void OnMediaPositionPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 37 { 38 var mediaElement = GetMediaElement(sender); 39 mediaElement.Position = TimeSpan.FromSeconds(GetMediaPosition(sender)); 40 } 41 42 /// <summary> 43 /// タイマーTick処理 44 /// </summary> 45 /// <param name="sender"></param> 46 /// <param name="e"></param> 47 private static void TimerTick(object sender, EventArgs e) 48 { 49 SetMediaPosition(_mediaElement, (long)_mediaElement.Position.TotalSeconds); 50 }
このMediaPositionProperty
に対してViewModelで定義したプロパティをBindingすることで再生位置の取得を行っています。
また、SliderのValueに同じプロパティをBindingすることで、MediaElementの再生位置をそのままSliderに反映させて、
Sliderの位置を変えたときにMediaElementに反映できるようにしています。
C#
1// VM----------------------------------------------------------------- 2 /// <summary> 3 /// 再生箇所 4 /// </summary> 5 public long MediaPosition 6 { 7 get => _mediaPosition; 8 set => SetProperty(ref _mediaPositionManager, value); 9 } 10// VM----------------------------------------------------------------- 11 12// View--------------------------------------------------------------- 13<MediaElement x:Name="MediaPlayer" Source="{Binding MediaSource, Mode=OneWay}" 14 b:MediaControlBehavior.MediaPosition="{Binding MediaPosition, Mode=TwoWay}"> 15 16<Slider x:Name="SeekBar" Value="{Binding MediaPosition, Mode=TwoWay}"/> 17// View---------------------------------------------------------------
ただし、この実装方法だと少し気持ちの悪い動きになってしまいます。
タイマーによる定期的なMediaElement.Positionの確認時、ビヘイビアで定義したMediaPositionProperty
に対して代入することで、
BindingされているVMのMediaPosition
に対して変更を行っていますが、タイマーによる再生位置の値がMediaPosition
に代入されると、
その変更通知がビヘイビアに戻ってきてしまいMediaElement.Positionに対して代入を行ってしまいます。
この無駄な動きが気持ち悪い上に、再生時間が多少前後してしまったりしてしまうため動作に影響も出てしまっています。
動画再生アプリを実装する際にシークバーの実装はよくあることだとは思うのですが、皆さんはどのようにして実装を行っているのでしょうか?
どのように改善したらいいのか、教えていただけないでしょうか?
よろしくお願いいたします。
長くなってしまった上に、質問したいこともうまくまとめられていない気がしますが、
足りない情報があればすぐに捕捉させていただきますのでよろしくお願いします。
言語:C#(.NET 5.0)
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/15 01:35