PowerShellでGUI: 可変個数RadioButton実現方法(別法)
「VisualStudioでPowerShell用GUIを作成する方法 - Itsukaraの日記」という記事で、PowerShellのGUI作成用にVisualStudioを使う方法を紹介し、可変個数のRadioButtonを表示する方法も書きました。しかし、可変個数のRadioButtonは、もっと良い実現方法を考えたので、紹介します。
とても簡単で、GUIの構造を表すXAML文字列を書き換えるだけです。下記にプログラム例を示します。下記の「add_items_to_xaml」という関数が、XAMLを書き換える処理です。汎用性があるので、RadioButton以外でも使えると思います。
- 可変個数のRadioButtonを作る例:
$ErrorActionPreference = "stop" Set-PSDebug -Strict Add-Type -AssemblyName PresentationFramework $xaml = @' <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="xaml test #2" Width="170pt" Height="170pt"> <StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel x:Name="country"> </StackPanel> <Label Content=" " FontSize="10pt"/> <StackPanel x:Name="fruit"> </StackPanel> </StackPanel> <Label x:Name="msg" Content=" " FontSize="10pt"/> <Button x:Name="btn" Content="Push Me" FontSize="10pt" /> </StackPanel> </Window> '@ # 項目一覧を$xamlに追加 # $head : 置換前文字列 # $add : 置換後文字列のひな型 # $placeholder: $add中のプレスホルダー文字列 # $items: 項目一覧(空白で区切られたワード列) function add_items_to_xaml($head, $add, $placeholder, $items) { $list = $items.split(" ") [array]::Reverse($list) foreach ($item in $list) { $add_item = $add.Replace($placeholder, $item) $global:xaml = $global:xaml.Replace($head, $add_item) } } # countryへの項目追加 $country_head = @' <StackPanel x:Name="country"> '@ $country_add = @' <StackPanel x:Name="country"> <RadioButton Content="PlaceHolder"></RadioButton> '@ $countries = "U.S.A China Japan Germany France England Russia" add_items_to_xaml $country_head $country_add "PlaceHolder" $countries # fruitへの項目追加 $fruit_head = @' <StackPanel x:Name="fruit"> '@ $fruit_add = @' <StackPanel x:Name="fruit"> <RadioButton Content="PlaceHolder"></RadioButton> '@ $fruits = "Apple Orange Grape" add_items_to_xaml $fruit_head $fruit_add "PlaceHolder" $fruits $xaml $xaml = [xml]$xaml $reader = New-Object System.Xml.XmlNodeReader $xaml $frm = [System.Windows.Markup.XamlReader]::Load($reader) $country = $frm.FindName("country") $fruit = $frm.FindName("fruit") $msg = $frm.FindName("msg") # 選択された項目を返す function getChecked($parent) { $checked = "" foreach ($child in $parent.Children) { if ($child.isChecked) { $checked += $child.Content } } return $checked } # ボタンクリック時の処理 function clicked { $selectedCountry = getChecked $country $selectedfruit = getChecked $fruit $msg.content = "Country=" + $selectedCountry + "`n" + "Fruit=" + $selectedfruit } $btn = $frm.FindName("btn") $btn.Add_Click({clicked}) $result = $frm.ShowDialog()
- 書換後のXAML(上記プログラムで出力したもの)
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="xaml test #2" Width="170pt" Height="170pt"> <StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <StackPanel x:Name="country"> <RadioButton Content="U.S.A"></RadioButton> <RadioButton Content="China"></RadioButton> <RadioButton Content="Japan"></RadioButton> <RadioButton Content="Germany"></RadioButton> <RadioButton Content="France"></RadioButton> <RadioButton Content="England"></RadioButton> <RadioButton Content="Russia"></RadioButton> </StackPanel> <Label Content=" " FontSize="10pt"/> <StackPanel x:Name="fruit"> <RadioButton Content="Apple"></RadioButton> <RadioButton Content="Orange"></RadioButton> <RadioButton Content="Grape"></RadioButton> </StackPanel> </StackPanel> <Label x:Name="msg" Content=" " FontSize="10pt"/> <Button x:Name="btn" Content="Push Me" FontSize="10pt" /> </StackPanel> </Window>
- 画面表示例:
あとがき
今回の件に関して、Webで色々と見つけたのですが、よい方法が見つからず、結局、自分で考えました。でも、後から考えると当たり前の内容であり、Webで色々調べた労力が無駄でした。