teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

見直しキャンペーン中

2023/07/27 16:01

投稿

TN8001
TN8001

スコア10111

answer CHANGED
@@ -1,246 +1,247 @@
1
- WPFはxamlとC#コードはセットですので、よほど長くない限り一緒に提示してください。
2
-
3
- > MediaEndedでどういった処理を書けばよいのか分からなくなりました。
4
-
5
- `Source`に新しいファイルをセットします。
6
- [MediaElement.Source プロパティ (System.Windows.Controls) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.controls.mediaelement.source)
7
-
8
- `OpenFileDialog`はWPFにもあるので、`System.Windows.Forms`を参照する必要はありません。
9
- [OpenFileDialog クラス (Microsoft.Win32) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.win32.openfiledialog)
10
-
11
- ---
12
-
13
- WPFの`MediaElement`はコントローラがないので、最低限の操作だけでも一苦労なんですよねぇ(UWPだと標準でオシャレなコントローラがついているのですが^^;
14
-
15
- [方法: MediaElement (再生、一時停止、停止、ボリューム、および速度) を制御する - WPF .NET Framework | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/graphics-multimedia/how-to-control-a-mediaelement-play-pause-stop-volume-and-speed)
16
- をベースにまともなシークバーにした参考実装です(シークバーは過去にいろいろ試しましたが、これが一番簡単で分かりやすいと思います)
17
-
18
- ```xaml
19
- <Window
20
- x:Class="Questions345578.MainWindow"
21
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
22
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
23
- Width="800"
24
- Height="450">
25
- <Grid>
26
- <Grid.ColumnDefinitions>
27
- <ColumnDefinition />
28
- <ColumnDefinition Width="10" />
29
- <ColumnDefinition Width="4*" />
30
- </Grid.ColumnDefinitions>
31
- <DockPanel>
32
- <Button
33
- Click="Open_Button_Click"
34
- Content="Open"
35
- DockPanel.Dock="Bottom" />
36
- <ListBox x:Name="TrackList" SelectionChanged="TrackList_SelectionChanged">
37
- <ListBox.ItemTemplate>
38
- <DataTemplate>
39
- <TextBlock Text="{Binding FileName}" ToolTip="{Binding FilePath}" />
40
- </DataTemplate>
41
- </ListBox.ItemTemplate>
42
- </ListBox>
43
- </DockPanel>
44
- <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
45
- <DockPanel Grid.Column="2" Background="Black">
46
- <StackPanel DockPanel.Dock="Bottom">
47
- <ProgressBar
48
- x:Name="seekBar"
49
- Height="20"
50
- MouseDown="SeekBar_MouseDown"
51
- MouseMove="SeekBar_MouseMove"
52
- MouseUp="SeekBar_MouseUp" />
53
- <Grid>
54
- <Grid.ColumnDefinitions>
55
- <ColumnDefinition />
56
- <ColumnDefinition Width="Auto" />
57
- <ColumnDefinition />
58
- </Grid.ColumnDefinitions>
59
- <Slider
60
- Name="volumeSlider"
61
- Width="100"
62
- HorizontalAlignment="Right"
63
- VerticalAlignment="Center"
64
- Maximum="1"
65
- ValueChanged="ChangeVolume"
66
- Value="0.5" />
67
- <StackPanel
68
- Grid.Column="1"
69
- HorizontalAlignment="Center"
70
- Orientation="Horizontal">
71
- <Button Click="OnPrevious" Content="⏮" />
72
- <Button Click="OnPlay" Content="⏵" />
73
- <Button Click="OnPause" Content="⏸" />
74
- <Button Click="OnStop" Content="⏹" />
75
- <Button Click="OnNext" Content="⏭" />
76
- </StackPanel>
77
- <TextBlock
78
- x:Name="textBlock"
79
- Grid.Column="2"
80
- HorizontalAlignment="Right"
81
- VerticalAlignment="Center"
82
- Foreground="White"
83
- Text="0:00:00 / 0:00:00" />
84
- </Grid>
85
- </StackPanel>
86
- <MediaElement
87
- Name="mediaElement"
88
- LoadedBehavior="Manual"
89
- MediaEnded="OnMediaEnded"
90
- MediaOpened="OnMediaOpened"
91
- ScrubbingEnabled="True"
92
- UnloadedBehavior="Stop" />
93
- </DockPanel>
94
- </Grid>
95
- </Window>
96
- ```
97
-
98
- ```C#
99
- using Microsoft.Win32;
100
- using System;
101
- using System.IO;
102
- using System.Windows;
103
- using System.Windows.Controls;
104
- using System.Windows.Input;
105
- using System.Windows.Threading;
106
-
107
- namespace Questions345578
108
- {
109
- class Item
110
- {
111
- public string FilePath { get; set; }
112
- public string FileName => Path.GetFileName(FilePath);
113
- }
114
-
115
- public partial class MainWindow : Window
116
- {
117
- private readonly DispatcherTimer timer; // 再生位置監視タイマ
118
- private bool isPlaying; // 再生中
119
- private bool isDragging; // シークバードラッグ中
120
-
121
- public MainWindow()
122
- {
123
- InitializeComponent();
124
- timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1), };
125
- timer.Tick += Timer_Tick;
126
- }
127
-
128
-
129
- private void Open_Button_Click(object sender, RoutedEventArgs e)
130
- {
131
- var ofd = new OpenFileDialog
132
- {
133
- Multiselect = true,
134
- InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos),
135
- };
136
-
137
- bool? result = ofd.ShowDialog(); // ダイアログを開きます。閉じるまで進みません。
138
- if (result == true) // OKの場合true。キャンセル・×の場合false。基本的にnullにはなりません。
139
- {
140
- foreach (var path in ofd.FileNames)
141
- TrackList.Items.Add(new Item { FilePath = path, });
142
- }
143
- }
144
-
145
- private void TrackList_SelectionChanged(object sender, SelectionChangedEventArgs e)
146
- {
147
- if (TrackList.SelectedItem is Item item)
148
- {
149
- mediaElement.Source = new Uri(item.FilePath);
150
- mediaElement.Play();
151
- isPlaying = true;
152
- }
153
- }
154
-
155
- private void OnMediaOpened(object sender, EventArgs e)
156
- {
157
- seekBar.Maximum = mediaElement.NaturalDuration.TimeSpan.TotalMilliseconds; // 総再生ミリ秒
158
- seekBar.Value = 0;
159
- timer.Start();
160
- }
161
- private void OnMediaEnded(object sender, EventArgs e)
162
- {
163
- mediaElement.Stop();
164
- timer.Stop();
165
- isPlaying = false;
166
- OnNext(null, null); // 雑に呼び出しw
167
- }
168
-
169
- private void OnPrevious(object sender, RoutedEventArgs e)
170
- {
171
- mediaElement.Stop();
172
- timer.Stop();
173
- if (0 < TrackList.SelectedIndex) // 前を選択できれば。。選択
174
- TrackList.SelectedIndex--;
175
- }
176
- private void OnNext(object sender, RoutedEventArgs e)
177
- {
178
- mediaElement.Stop();
179
- timer.Stop();
180
- if (TrackList.SelectedIndex < TrackList.Items.Count - 1) // 後を選択できれば。。選択
181
- TrackList.SelectedIndex++;
182
- }
183
-
184
- private void Timer_Tick(object sender, EventArgs e)
185
- {
186
- seekBar.Value = mediaElement.Position.TotalMilliseconds;
187
- var position = mediaElement.Position; // 再生現在位置
188
- var total = mediaElement.NaturalDuration.TimeSpan; // 総再生時間
189
- textBlock.Text = $"{position:h\:mm\:ss} / {total:h\:mm\:ss}";
190
- }
191
-
192
- private void SeekBar_MouseDown(object sender, MouseButtonEventArgs e)
193
- {
194
- isDragging = true;
195
- seekBar.CaptureMouse(); // MouseUpを確実にとるためキャプチャ
196
-
197
- // 総再生ミリ秒 * シーク位置の割合(例えば真ん中だったら0.5)
198
- seekBar.Value = seekBar.Maximum * (e.GetPosition(seekBar).X / seekBar.ActualWidth);
199
- mediaElement.Position = TimeSpan.FromMilliseconds(seekBar.Value); // seekBar.Valueはミリ秒単位なので
200
-
201
- mediaElement.Pause(); // PlayしながらシークするとガチャつくのでPause
202
- }
203
- private void SeekBar_MouseMove(object sender, MouseEventArgs e)
204
- {
205
- if (isDragging)
206
- {
207
- seekBar.Value = seekBar.Maximum * (e.GetPosition(seekBar).X / seekBar.ActualWidth);
208
- mediaElement.Position = TimeSpan.FromMilliseconds(seekBar.Value);
209
- }
210
- }
211
- private void SeekBar_MouseUp(object sender, MouseButtonEventArgs e)
212
- {
213
- isDragging = false;
214
- seekBar.ReleaseMouseCapture();
215
- mediaElement.Position = TimeSpan.FromMilliseconds(seekBar.Value);
216
- if (isPlaying) mediaElement.Play(); // Play状態復元
217
- }
218
-
219
- private void OnPlay(object sender, RoutedEventArgs args)
220
- {
221
- mediaElement.Play();
222
- timer.Start();
223
- isPlaying = true;
224
-
225
- }
226
- private void OnPause(object sender, RoutedEventArgs e)
227
- {
228
- mediaElement.Pause();
229
- timer.Stop();
230
- isPlaying = false;
231
- }
232
- private void OnStop(object sender, RoutedEventArgs e)
233
- {
234
- mediaElement.Stop();
235
- timer.Stop();
236
- isPlaying = false;
237
- }
238
-
239
- private void ChangeVolume(object sender, RoutedPropertyChangedEventArgs<double> args)
240
- {
241
- if (mediaElement != null)
242
- mediaElement.Volume = volumeSlider.Value;
243
- }
244
- }
245
- }
246
- ```
1
+ WPFはxamlとC#コードはセットですので、よほど長くない限り一緒に提示してください。
2
+
3
+ > MediaEndedでどういった処理を書けばよいのか分からなくなりました。
4
+
5
+ `Source`に新しいファイルをセットします。
6
+ [MediaElement.Source プロパティ (System.Windows.Controls) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.controls.mediaelement.source)
7
+
8
+ `OpenFileDialog`はWPFにもあるので、`System.Windows.Forms`を参照する必要はありません。
9
+ [OpenFileDialog クラス (Microsoft.Win32) | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.win32.openfiledialog)
10
+
11
+ ---
12
+
13
+ WPFの`MediaElement`はコントローラがないので、最低限の操作だけでも一苦労なんですよねぇ(UWPだと標準でオシャレなコントローラがついているのですが^^;
14
+
15
+ [方法: MediaElement (再生、一時停止、停止、ボリューム、および速度) を制御する - WPF .NET Framework | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/graphics-multimedia/how-to-control-a-mediaelement-play-pause-stop-volume-and-speed)
16
+ をベースにまともなシークバーにした参考実装です(シークバーは過去にいろいろ試しましたが、これが一番簡単で分かりやすいと思います)
17
+
18
+ ```xml
19
+ <Window
20
+ x:Class="Questions345578.MainWindow"
21
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
22
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
23
+ Width="800"
24
+ Height="450">
25
+ <Grid>
26
+ <Grid.ColumnDefinitions>
27
+ <ColumnDefinition />
28
+ <ColumnDefinition Width="10" />
29
+ <ColumnDefinition Width="4*" />
30
+ </Grid.ColumnDefinitions>
31
+ <DockPanel>
32
+ <Button
33
+ Click="Open_Button_Click"
34
+ Content="Open"
35
+ DockPanel.Dock="Bottom" />
36
+ <ListBox x:Name="TrackList" SelectionChanged="TrackList_SelectionChanged">
37
+ <ListBox.ItemTemplate>
38
+ <DataTemplate>
39
+ <TextBlock Text="{Binding FileName}" ToolTip="{Binding FilePath}" />
40
+ </DataTemplate>
41
+ </ListBox.ItemTemplate>
42
+ </ListBox>
43
+ </DockPanel>
44
+ <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
45
+ <DockPanel Grid.Column="2" Background="Black">
46
+ <StackPanel DockPanel.Dock="Bottom">
47
+ <ProgressBar
48
+ x:Name="seekBar"
49
+ Height="20"
50
+ MouseDown="SeekBar_MouseDown"
51
+ MouseMove="SeekBar_MouseMove"
52
+ MouseUp="SeekBar_MouseUp" />
53
+ <Grid>
54
+ <Grid.ColumnDefinitions>
55
+ <ColumnDefinition />
56
+ <ColumnDefinition Width="Auto" />
57
+ <ColumnDefinition />
58
+ </Grid.ColumnDefinitions>
59
+ <Slider
60
+ Name="volumeSlider"
61
+ Width="100"
62
+ HorizontalAlignment="Right"
63
+ VerticalAlignment="Center"
64
+ Maximum="1"
65
+ ValueChanged="ChangeVolume"
66
+ Value="0.5" />
67
+ <StackPanel
68
+ Grid.Column="1"
69
+ HorizontalAlignment="Center"
70
+ Orientation="Horizontal">
71
+ <Button Click="OnPrevious" Content="⏮" />
72
+ <Button Click="OnPlay" Content="⏵" />
73
+ <Button Click="OnPause" Content="⏸" />
74
+ <Button Click="OnStop" Content="⏹" />
75
+ <Button Click="OnNext" Content="⏭" />
76
+ </StackPanel>
77
+ <TextBlock
78
+ x:Name="textBlock"
79
+ Grid.Column="2"
80
+ HorizontalAlignment="Right"
81
+ VerticalAlignment="Center"
82
+ Foreground="White"
83
+ Text="0:00:00 / 0:00:00" />
84
+ </Grid>
85
+ </StackPanel>
86
+ <MediaElement
87
+ Name="mediaElement"
88
+ LoadedBehavior="Manual"
89
+ MediaEnded="OnMediaEnded"
90
+ MediaOpened="OnMediaOpened"
91
+ ScrubbingEnabled="True"
92
+ UnloadedBehavior="Stop" />
93
+ </DockPanel>
94
+ </Grid>
95
+ </Window>
96
+ ```
97
+
98
+ ```cs
99
+ using Microsoft.Win32;
100
+ using System;
101
+ using System.IO;
102
+ using System.Windows;
103
+ using System.Windows.Controls;
104
+ using System.Windows.Input;
105
+ using System.Windows.Threading;
106
+
107
+ namespace Questions345578
108
+ {
109
+ class Item
110
+ {
111
+ public string FilePath { get; set; }
112
+ public string FileName => Path.GetFileName(FilePath);
113
+ }
114
+
115
+ public partial class MainWindow : Window
116
+ {
117
+ private readonly DispatcherTimer timer; // 再生位置監視タイマ
118
+ private bool isPlaying; // 再生中
119
+ private bool isDragging; // シークバードラッグ中
120
+
121
+ public MainWindow()
122
+ {
123
+ InitializeComponent();
124
+ timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1), };
125
+ timer.Tick += Timer_Tick;
126
+ }
127
+
128
+
129
+ private void Open_Button_Click(object sender, RoutedEventArgs e)
130
+ {
131
+ var ofd = new OpenFileDialog
132
+ {
133
+ Multiselect = true,
134
+ InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos),
135
+ };
136
+
137
+ bool? result = ofd.ShowDialog(); // ダイアログを開きます。閉じるまで進みません。
138
+ if (result == true) // OKの場合true。キャンセル・×の場合false。基本的にnullにはなりません。
139
+ {
140
+ foreach (var path in ofd.FileNames)
141
+ TrackList.Items.Add(new Item { FilePath = path, });
142
+ }
143
+ }
144
+
145
+ private void TrackList_SelectionChanged(object sender, SelectionChangedEventArgs e)
146
+ {
147
+ if (TrackList.SelectedItem is Item item)
148
+ {
149
+ mediaElement.Source = new Uri(item.FilePath);
150
+ mediaElement.Play();
151
+ isPlaying = true;
152
+ }
153
+ }
154
+
155
+ private void OnMediaOpened(object sender, EventArgs e)
156
+ {
157
+ seekBar.Maximum = mediaElement.NaturalDuration.TimeSpan.TotalMilliseconds; // 総再生ミリ秒
158
+ seekBar.Value = 0;
159
+ timer.Start();
160
+ }
161
+ private void OnMediaEnded(object sender, EventArgs e)
162
+ {
163
+ mediaElement.Stop();
164
+ timer.Stop();
165
+ isPlaying = false;
166
+ OnNext(null, null); // 雑に呼び出しw
167
+ }
168
+
169
+ private void OnPrevious(object sender, RoutedEventArgs e)
170
+ {
171
+ mediaElement.Stop();
172
+ timer.Stop();
173
+ if (0 < TrackList.SelectedIndex) // 前を選択できれば。。選択
174
+ TrackList.SelectedIndex--;
175
+ }
176
+ private void OnNext(object sender, RoutedEventArgs e)
177
+ {
178
+ mediaElement.Stop();
179
+ timer.Stop();
180
+ if (TrackList.SelectedIndex < TrackList.Items.Count - 1) // 後を選択できれば。。選択
181
+ TrackList.SelectedIndex++;
182
+ }
183
+
184
+ private void Timer_Tick(object sender, EventArgs e)
185
+ {
186
+ seekBar.Value = mediaElement.Position.TotalMilliseconds;
187
+ var position = mediaElement.Position; // 再生現在位置
188
+ var total = mediaElement.NaturalDuration.TimeSpan; // 総再生時間
189
+ textBlock.Text = $"{position:h\:mm\:ss} / {total:h\:mm\:ss}";
190
+ }
191
+
192
+ private void SeekBar_MouseDown(object sender, MouseButtonEventArgs e)
193
+ {
194
+ isDragging = true;
195
+ seekBar.CaptureMouse(); // MouseUpを確実にとるためキャプチャ
196
+
197
+ // 総再生ミリ秒 * シーク位置の割合(例えば真ん中だったら0.5)
198
+ seekBar.Value = seekBar.Maximum * (e.GetPosition(seekBar).X / seekBar.ActualWidth);
199
+ mediaElement.Position = TimeSpan.FromMilliseconds(seekBar.Value); // seekBar.Valueはミリ秒単位なので
200
+
201
+ mediaElement.Pause(); // PlayしながらシークするとガチャつくのでPause
202
+ }
203
+ private void SeekBar_MouseMove(object sender, MouseEventArgs e)
204
+ {
205
+ if (isDragging)
206
+ {
207
+ seekBar.Value = seekBar.Maximum * (e.GetPosition(seekBar).X / seekBar.ActualWidth);
208
+ mediaElement.Position = TimeSpan.FromMilliseconds(seekBar.Value);
209
+ }
210
+ }
211
+ private void SeekBar_MouseUp(object sender, MouseButtonEventArgs e)
212
+ {
213
+ isDragging = false;
214
+ seekBar.ReleaseMouseCapture();
215
+ mediaElement.Position = TimeSpan.FromMilliseconds(seekBar.Value);
216
+ if (isPlaying) mediaElement.Play(); // Play状態復元
217
+ }
218
+
219
+ private void OnPlay(object sender, RoutedEventArgs args)
220
+ {
221
+ mediaElement.Play();
222
+ timer.Start();
223
+ isPlaying = true;
224
+
225
+ }
226
+ private void OnPause(object sender, RoutedEventArgs e)
227
+ {
228
+ mediaElement.Pause();
229
+ timer.Stop();
230
+ isPlaying = false;
231
+ }
232
+ private void OnStop(object sender, RoutedEventArgs e)
233
+ {
234
+ mediaElement.Stop();
235
+ timer.Stop();
236
+ isPlaying = false;
237
+ }
238
+
239
+ private void ChangeVolume(object sender, RoutedPropertyChangedEventArgs<double> args)
240
+ {
241
+ if (mediaElement != null)
242
+ mediaElement.Volume = volumeSlider.Value;
243
+ }
244
+ }
245
+ }
246
+ ```
247
+ ![アプリ画像](https://ddjkaamml8q8x.cloudfront.net/questions/2023-07-28/9cc66d6a-dbf5-4b7b-a854-6c601bc7cd17.png)