質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

910閲覧

MediaPlayerElementの再生位置をSliderでうまく操作できない

junyasu0124

総合スコア38

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1グッド

0クリップ

投稿2023/02/05 15:21

前提、実現したいこと

WinUI3で動画を再生できるページを作っています。MediaPlayerElementで動画を再生し、そのAreTransportControlsEnabledをFalseにして自分で動画再生のコントロールを作ろうとしています。Sliderを使って再生位置を変えられるようにしているのですが、動画再生中にSliderのつまみをもって少し動かした後どこかでつまみを持ったまま同じ場所でとどまると、動画は進もうとしていくのにSliderはそれより前の位置にしようとするので、動画が少し再生されてそのあとすぐ巻き戻るという動きを繰り返してしまいます。

試したこと

Sliderを動かしている間は動画の再生を止めようと思ったのですが、SliderのValueがつまみを動かすことによって変更されたということを検知する方法がわかりませんでした。SliderのTappedはマウスが押された場所と離された場所が同じでないと発火しないようなのでうまくいきませんでした。
また、下のSlider_ValueChangedは動画が再生されると何度も発火し、発火した原因がユーザーの操作によってなのか、単に動画が再生されているからなのかを見分ける方法がわからないので、その中に動画の再生を一時停止するなどといった処理を入れられませんでした。

ソースコード

SliderのValueから動画の再生位置を決める

C#

1private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) 2{ 3 var value = (sender as Slider).Value; 4 mediaPlayer.PlaybackSession.Position = new TimeSpan(0, 0, 0, 0, (int)value); 5 //VideoPlayer.SetMediaPlayer(mediaPlayer); が前のほうにあります。 6}

SliderのValueを動画の再生時間に同期

C#

1mediaPlayer.PlaybackSession.PositionChanged += MediaPlayerPositionChanged; 2private void MediaPlayerPositionChanged(MediaPlaybackSession sender, object e) 3{ 4 VideoCommandSlider.Value = mediaPlayer.PlaybackSession.Position.TotalMilliseconds; 5}
TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

len_souko

2023/02/05 23:00

WinUI3はほとんど触っていないうえにMediaPlayerElementはノータッチでしたので見当違いかもしれませんが、イベント的には 押す=>(動かす)=>離す で、動かすがない場合にTappedが発生するので、やりたいことをするタイミングではないかと思います また、「スライダーを止めた場合」の処理がしたいのにValueChangedも起きる筈がありませんので見当違いかと思います 調べるべきは押すイベントで再生を止めて話すイベントで再生を再開というのが一番自然な動きになりそうなのでそのイベントをどうやってとるかを調べると良いと思います
guest

回答1

0

ベストアンサー

WPFみたいにPreview系のイベントがないのがつらいですね^^;

SliderのValueがつまみを動かすことによって変更されたということを検知する方法がわかりませんでした。

Sliderのテンプレートを見ると、CommonStates.Pressedで検知できそうです。
microsoft-ui-xaml/controls/dev/CommonStyles/Slider_themeresources.xaml at winui3/release/1.4-stable · microsoft/microsoft-ui-xaml

PlaybackSession.PositionChangedはあんまりスムーズではなかったので、単純にタイマーにしました(が、処理が甘いかもw

xml

1<windowex:WindowEx 2 x:Class="Qbcc389s6g38ght.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:windowex="using:WinUIEx" 6 Width="800" 7 Height="450"> 8 9 <Grid RowDefinitions="*,Auto"> 10 <MediaPlayerElement x:Name="mpe" Source="ms-appx:///Assets/SampleMedia/ladybug.wmv" /> 11 12 <StackPanel Grid.Row="1" Margin="8"> 13 <Slider 14 x:Name="slider" 15 Loaded="Slider_Loaded" 16 ValueChanged="Slider_ValueChanged" /> 17 18 <ToggleButton 19 x:Name="toggleButton" 20 HorizontalAlignment="Center" 21 Checked="ToggleButton_Checked" 22 Content="Play/Pause" 23 Unchecked="ToggleButton_Unchecked" /> 24 </StackPanel> 25 </Grid> 26</windowex:WindowEx>

cs

1using System; 2using System.Linq; 3using Microsoft.UI.Dispatching; 4using Microsoft.UI.Xaml; 5using Microsoft.UI.Xaml.Controls.Primitives; 6using Microsoft.UI.Xaml.Media; 7using Windows.Media.Playback; 8 9namespace Qbcc389s6g38ght; 10 11public sealed partial class MainWindow //: Window 12{ 13 private readonly DispatcherTimer timer; 14 private bool isPlaying; 15 16 public MainWindow() 17 { 18 InitializeComponent(); 19 20 mpe.MediaPlayer.MediaOpened += MediaPlayer_MediaOpened; 21 mpe.MediaPlayer.MediaEnded += MediaPlayer_MediaEnded; 22 23 mpe.MediaPlayer.PlaybackSession.PlaybackStateChanged += PlaybackSession_PlaybackStateChanged; 24 25 timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(100), }; 26 timer.Tick += Timer_Tick; 27 } 28 29 30 private void Slider_Loaded(object sender, RoutedEventArgs e) 31 { 32 var firstChild = VisualTreeHelper.GetChild(slider, 0) as FrameworkElement; 33 var commonStates = VisualStateManager.GetVisualStateGroups(firstChild) 34 .First(x => x.Name == "CommonStates"); 35 commonStates.CurrentStateChanged += CommonStates_CurrentStateChanged; 36 } 37 private void CommonStates_CurrentStateChanged(object sender, VisualStateChangedEventArgs e) 38 { 39 if (e.NewState.Name == "Pressed") 40 { 41 isPlaying = mpe.MediaPlayer.PlaybackSession.PlaybackState == MediaPlaybackState.Playing; 42 mpe.MediaPlayer.Pause(); 43 } 44 else if (e.NewState.Name == "Normal") 45 { 46 if (isPlaying) mpe.MediaPlayer.Play(); 47 } 48 } 49 50 private void MediaPlayer_MediaOpened(MediaPlayer sender, object args) 51 { 52 DispatcherQueue?.TryEnqueue(DispatcherQueuePriority.Normal, () => 53 { 54 slider.Maximum = mpe.MediaPlayer.PlaybackSession.NaturalDuration.TotalMilliseconds; 55 }); 56 } 57 private void MediaPlayer_MediaEnded(MediaPlayer sender, object args) 58 { 59 DispatcherQueue?.TryEnqueue(DispatcherQueuePriority.Normal, () => 60 { 61 slider.Value = 0; 62 toggleButton.IsChecked = false; 63 }); 64 } 65 66 private void PlaybackSession_PlaybackStateChanged(MediaPlaybackSession sender, object args) 67 { 68 DispatcherQueue?.TryEnqueue(DispatcherQueuePriority.Normal, () => 69 { 70 if (mpe.MediaPlayer.PlaybackSession.PlaybackState == MediaPlaybackState.Playing) 71 timer.Start(); 72 else 73 timer.Stop(); 74 }); 75 } 76 77 private void Timer_Tick(object sender, object e) 78 => slider.Value = mpe.MediaPlayer.PlaybackSession.Position.TotalMilliseconds; 79 80 private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) 81 => mpe.MediaPlayer.PlaybackSession.Position = TimeSpan.FromMilliseconds(slider.Value); 82 83 private void ToggleButton_Checked(object sender, RoutedEventArgs e) => mpe.MediaPlayer.Play(); 84 private void ToggleButton_Unchecked(object sender, RoutedEventArgs e) => mpe.MediaPlayer.Pause(); 85}

NuGet Gallery | WinUIEx 2.1.0


わたしも今MediaTransportControlsで見切れるシークバー(↓のようなの)を作ってるんですが、隠れると位置が更新されなくて頭を抱えました(結局2重にSliderを付けたw
[WPF] 動画プレイヤー 表示/非表示できる操作画面を作りたい

ThumbnailRequestedもタップした時しか来ないとか意味が分からんし...

投稿2023/02/05 23:35

編集2024/02/23 07:03
TN8001

総合スコア9326

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

junyasu0124

2023/02/06 17:12

回答ありがとうございます。思い通りの挙動になりました。CommonStatesを使ったイベントを作れることを初めて知りました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問