前回は、ConsoleでMedia Playerを作成しました。その後、Windows.Form を使ってのものも作成しましたが、ここには最終的に作成した WPF を取り入れたMedia Playerの作成過程をご紹介します。
WPFでWindowを表示
先ずは、PowerShell で WPFを使用してWindowを表示してみます。最初は、ListBox をWindowに表示するだけのプログラムです。
$loadXaml1 =@'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Play Music"
FontFamily="MS ゴシック"
Height="660"
Width="750"
Margin="5"
>
<StackPanel>
<ListBox
Name="listbox"
FontSize="12"
Background="#8888FF"
Height="505"
Margin="0"
SelectionMode="Single"
/>
</StackPanel>
</Window>
'@
function PlayMusic{
[CmdletBinding(
SupportsShouldProcess = $false,
ConfirmImpact = "none",
DefaultParameterSetName = ""
)]
param
(
[Parameter(
HelpMessage = "Load binding Xaml you defined beforehands",
Position = 0,
Mandatory = $true,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)]
[ValidateNotNullOrEmpty()]
[string]
$loadXaml1,
[Alias("PassThru")]
[switch]
$PassThrough
)
begin
{
try
{
# Add-Typeでアセンブリをロードする
Add-Type -AssemblyName presentationframework
}
catch
{
#Alread Type added.
}
try
{
[xml]$xaml = $loadXaml1
}
catch
{
}
}
process
{
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$window=[Windows.Markup.XamlReader]::Load( $reader )
$lstBox = $window.FindName("listbox")
}
end
{
$window.ShowDialog() | out-null
return [PSCustomObject]@{
}
}
}
######## End of Function PlayMusic
PlayMusic -loadXaml $loadXaml1
実行すると次のようなWindowが表示されます。

List Box にプレイする曲をリストアップ
次に表示したList Box にプレイする曲をリストアップするコードを記述します。
- playlist.txt にmp3,m4a ファイルへの絶対パスのリストがあるものとします。
- 30項目を1ページとします。
- 現在表示中のページは、$global:PageDisp というグローバル変数に入っているものとし、現在1ページです。
########## Functions ###############################
####### #ListBox initialize
Function ListBoxAdd {
[void]$lstBox.Items.Clear()
$Lines0 = cat PlayList.txt | ? { $_ -ne '' } #すべてを $Lines 配列に格納
if ($Lines0.count -eq 1 ) { $Lines0 = @($Lines0) }
$Lines = $Lines0
write-host $Lines.count
if ( $Lines.count -eq 0 ) { Return }
$Global:TotalLines = $Lines.count
$TotalPage = [math]::Ceiling($Global:TotalLines / 30) # 1 page を 30 として Total page 数を算出
$Tps = "{0:D2}" -f [int]$TotalPage
$lblTotalP.content = $Tps
$Amari = $Global:TotalLines % 30
If ($Amari -eq 0 ) { $Amari = 30 }
# $global:pageDisp = [int]$lblPage.content
$Page = $global:pageDisp - 1
$II = $Page*30 ; # Page 0 start で 現page に表示するLine の最初のインデックス
$E = $Page * 30 + 29
# 表示する最後のインデックス
If ( $Page -eq 0 -and $Global:TotalLines -eq 30 ) { $E = 29 }
If ( $Page -eq 0 -and $Global:TotalLines -lt 30 ) { $E = $Global:TotalLines - 1 }
if ( $Page -ge 1 -and $Page -eq ($TotalPage - 1)) { $E = ( ($TotalPage - 1) * 30 ) + ( $Amari - 1) }
for ($jj = $II; $jj -le $E ; $jj++ ) {
[Void]$lstBox.Items.Add($Lines[$jj])
}
$lstBox.SelectedIndex = 0
Return $page
} ##### Function ListBoxAdd END
#################### Main #########################
$global:pageDisp = 1
ListBoxAdd
#################### Main End ######################
PlayList.txt には次のようなテキストが入っています。
I:\Multimedia\itunes\Music\The Ventures\ザ・ベンチャーズ\The Ventures - Caravan.mp3
I:\Multimedia\itunes\Music\The Ventures\ザ・ベンチャーズ\The Ventures - Diamond Head.mp3
I:\Multimedia\ザ・ベンチャーズ\01 Diamond Head.mp3
I:\Multimedia\ザ・ベンチャーズ\02 Slaughter On The 10th Avenue.mp3
I:\Multimedia\ザ・ベンチャーズ\03 Apache.mp3
I:\Multimedia\ザ・ベンチャーズ\04 Walk Don't Run '64.mp3
I:\Multimedia\ザ・ベンチャーズ\05 House Of The Rising Sun.mp3
I:\Multimedia\ザ・ベンチャーズ\06 Driving Guitars.mp3
I:\Multimedia\ザ・ベンチャーズ\07 Surf Rider.mp3
I:\Multimedia\ザ・ベンチャーズ\08 Out Of Limits.mp3
I:\Multimedia\ザ・ベンチャーズ\09 Pipe Line.mp3
I:\Multimedia\ザ・ベンチャーズ\10 Caravan.mp3
I:\Multimedia\ザ・ベンチャーズ\11 Blue Star.mp3
I:\Multimedia\ザ・ベンチャーズ\12 Journey To The Stars.mp3
I:\Multimedia\ザ・ベンチャーズ\13 Wipe Out.mp3
I:\Multimedia\ザ・ベンチャーズ\14 I Feel Fine.mp3
I:\Multimedia\ザ・ベンチャーズ\15 Bulldog.mp3
I:\Multimedia\ザ・ベンチャーズ\16 Yellow Jacket.mp3
I:\Multimedia\ザ・ベンチャーズ\17 Perfidia.mp3
I:\Multimedia\ザ・ベンチャーズ\18 Lullaby Of The Leaves.mp3
I:\Multimedia\僕たちの洋楽ヒット Vol.04\ベンチャーズ - 京都の恋.mp3
実行するとつぎの様な表示がでます。

Page を表示する
1ページは30項目ですので、リスト項目が30以上になると複数ページになります。従ってページ番号を表示する必要があります。次の様にPanel内にCanvas を設けページ番号を表示するLabel を配置します。
<StackPanel>
<Canvas>
<Label
Canvas.Top="0"
Canvas.Left="300"
Name="LabelP1"
Content="Page "
FontSize="11"
Height="20"
Background="#FF8888"
Margin="2"
/>
<Label
Canvas.Top="0"
Canvas.Left="330"
Name="LabelPage"
Content="01"
FontSize="11"
Height="20"
Background="#FF8888"
Margin="2"
/>
<Label
Canvas.Top="0"
Canvas.Left="347"
Name="Labelof"
Content="/"
FontSize="11"
Height="20"
Background="#FF8888"
Margin="2"
/>
<Label
Canvas.Top="0"
Canvas.Left="357"
Name="LabelTopa"
Content="03"
FontSize="11"
Height="20"
Background="#FF8888"
Margin="2"
/>
</Canvas>
<ListBox
Name="listbox"
FontSize="12"
Background="#8888FF"
Height="505"
Margin="25"
SelectionMode="Single"
/>
</StackPanel>
Name=”LabelPage” が現在のページ 、Name=”LabelTopa” が Total Page です。
次の様に Label を定義します。
$lblTotalP = $window.FindName("LabelTopa")
$lblPage = $window.FindName("LabelPage")
実行すると、次の様に Page 01 / 01 と表示されます。

長いplaylistを読み込むと、次の様に Total Page 数が変わります。

Page を切り替える
複数ページに渡る場合にページを切り替える様にします。先ず、Page Up/Page Down するために Button を配置します。
<Button
Canvas.Top="0"
Canvas.Right="180"
Name="buttonPageUp"
Content="Page Up"
FontSize="12"
Foreground="#FFFFFF"
Background="#0F0F0F"
Height="20"
Margin="2"
/>
<Button
Canvas.Top="0"
Canvas.Right="80"
Name="buttonPageDown"
Content="Page Down"
FontSize="12"
Foreground="#FFFFFF"
Background="#0F0F0F"
Height="20"
Margin="2"
/>
実行すると、次の様に PageUp PageDown のボタンが表示されます。

PageUp PageDown のためのコードを記述します。
Button を定義します。
$buttonPageUp = $window.FindName("buttonPageUp")
$buttonPageDown = $window.FindName("buttonPageDown")
$buttonPageUp $buttonPageDown がクリックされた時に実行するコードを次の様に記述します。
$buttonPageUp_clicked = $buttonPageUp.add_Click
$buttonPageUp_clicked.Invoke({
$global:pageDisp = [int]$lblPage.content
if ( $global:pageDisp -le 1 ) { return }
$global:pageDisp--
$lblPage.content = "{0:D2}" -f $global:pageDisp
ListBoxAdd
})
$buttonPageDown_clicked = $buttonPageDown.add_Click
$buttonPageDown_clicked.Invoke({
$pageTotal = [int]$lblTotalP.content
$global:pageDisp = [int]$lblPage.content
if ( $global:pageDisp -ge $pageTotal ) { return }
$global:pageDisp++
$lblPage.content = "{0:D2}" -f $global:pageDisp
ListBoxAdd
})
実行すると、

Page Down をクリックすると

ListBox で選択されている曲をプレイ
いよいよ曲のプレイです。ListBoxの中で選択されている項目の曲をプレイします。
Powershell で MediaPlayer を使うために、以下のコードを先頭に記述しておきます。
add-type -assemblyname presentationcore
$mediaplayer = new-object system.windows.media.mediaplayer
PlayするためのButton を配置します。
<Canvas>
<Button
Canvas.Top="0"
Canvas.Left="20"
Name="buttonPlay"
Content="▶"
FontSize="14"
Foreground="#FFFFFF"
Background="#505050"
Height="20"
Margin="2"
/>
</Canvas>
以下の通り、左下に プレイボタンが表示されます。

$ButtonPlay を定義します。
$buttonPlay = $window.FindName("buttonPlay")
Play ボタンを押した時に実行するコードを記述します。
$buttonPlay_clicked = $buttonPlay.add_Click #### Play ボタン
$buttonPlay_clicked.Invoke({
if ( $lstbox.SelectedIndex -eq -1 ) { $lstbox.SelectedIndex = 0 }
$global:kyoku = $lstbox.SelectedItem
if ( !( Test-path -literalpath $global:kyoku ) ) { $lstbox.SelectedIndex++ ; return }
$MediaPlayer.Stop()
$buttonPlay.isEnabled = $False
$MediaPlayer.Open($global:kyoku)
$MediaPlayer.Play()
})
これでPlayボタンを押せば、選択されている曲がプレイされる Media Player が出来ました。しかし、演奏の中止、ポーズ、次の曲へのスキップ等は一切出来ません。
Exit ボタンでプログラム中止、曲の演奏中止
Windowの右上の X でプログラムを中止しても、一旦演奏開始した曲は終わるまで止まりません。Exit ボタンを設けてプログラムの中止で演奏も止まるようにします。
buttonExit を配置します。
<Button
Canvas.Top="0"
Canvas.Right="20"
Name="buttonExit"
Content="EXIT"
FontSize="14"
Foreground="#FFFFFF"
Background="#505050"
Height="20"
Margin="2"
/>
$buttonExit を定義して、クリックした時の実行コードを以下の様に記述します。
$buttonExit = $window.FindName("buttonExit")
$buttonExit_clicked = $buttonExit.add_Click
$buttonExit_clicked.Invoke({
$MediaPlayer.Stop()
$Window.close()
})
実行すること

これで、プレイした後に途中で Exit ボタンでプログラムを Exitすれば 曲の演奏も止まります。
Next ボタンで次の曲を再生
Next >| よくあるこんなボタンで次の曲を再生する様にします。
buttonNext を配置します。
<Button
Canvas.Top="0"
Canvas.Left="70"
Name="buttonNext"
Content=">|"
FontSize="14"
Foreground="#FFFFFF"
Background="#505050"
Height="20"
Margin="2"
/>
$buttonNextを定義して、クリックした時に実行するコードを次の様に記述します。
$buttonNext = $window.FindName("buttonNext")
$buttonNext_clicked = $buttonNext.add_Click ####### ボタン Next ###############
$buttonNext_clicked.Invoke({
$mediaplayer.Stop()
$lstBox.SelectedIndex++
$global:kyoku = $lstBox.SelectedItem
$mediaplayer.open($global:kyoku)
$MediaPlayer.Play()
})
ここまでで、Playするコードが PlayボタンとNextボタンに記述されていますが、今後のために Playするコードを Function にまとめておきます。
function StartPlay {
if ( $lstbox.SelectedIndex -eq -1 ) { $lstbox.SelectedIndex = 0 }
$global:kyoku = $lstbox.SelectedItem
if ( !( Test-path -literalpath $global:kyoku ) ) { $lstbox.SelectedIndex++ ; return }
$MediaPlayer.Stop()
$buttonPlay.isEnabled = $False
$MediaPlayer.Open($global:kyoku)
$MediaPlayer.Play()
}
$buttonPlay_clicked = $buttonPlay.add_Click #### Play ボタン
$buttonPlay_clicked.Invoke({
StartPlay
})
$buttonExit_clicked = $buttonExit.add_Click
$buttonExit_clicked.Invoke({
$MediaPlayer.Stop()
$Window.close()
})
$buttonNext_clicked = $buttonNext.add_Click ####### ボタン Next ###############
$buttonNext_clicked.Invoke({
$lstBox.SelectedIndex++
StartPlay
})
曲が終わったら自動的に次の曲を再生
Play ボタンで再生、Next ボタンで次の曲へ行くことが出来るようになりました。次は現在の曲が終われば自動的に次の曲を再生する様にしたいと思います。曲が終わった事を検知する為に Timer を使います。
Timer を使うために次のコードをスクリプトの先頭に記述します。
$TimerObject = [System.Windows.Forms.Timer]
$timerX1 = New-Object $TimerObject
プレイしたと同時にTimerに曲の長さと同じ秒数(Milliseconds)のInterval をセットしTimerがExpireすれば曲が終わったと判断します。
曲の長さは、$MediaPlayer.Open() した後、$mediaplayer.NaturalDuration.TimeSpan.TotalMilliSeconds で知ることが出来ます。
PS >add-type -assemblyname presentationcore
PS >$mediaplayer = new-object system.windows.media.mediaplayer
PS >$mediaplayer.open("I:\MultiMedia\小椋佳\小椋佳 - 白い一日.mp3")
PS >$mediaplayer.NaturalDuration.TimeSpan
Days : 0
Hours : 0
Minutes : 3
Seconds : 16
Milliseconds : 475
Ticks : 1964754583
TotalDays : 0.00227402150810185
TotalHours : 0.0545765161944444
TotalMinutes : 3.27459097166667
TotalSeconds : 196.4754583
TotalMilliseconds : 196475.4583
PS >$mediaplayer.NaturalDuration.TimeSpan.TotalMilliseconds
196475.4583
PS >[int]$mediaplayer.NaturalDuration.TimeSpan.TotalMilliSeconds
196475