こんな感じのボタンを押すとアイコンを選択する Flyout を表示する場合、アイコンが画像ならば Uri を ViewModel に持っておけば Binding も簡単なんですが・・・
こういうアイコンはやっぱり拡縮で劣化しないベクター素材の Path で表示したい!
ViewModel に Path の Data プロパティ用の文字列を持たせてみましたが、 Binding でエラーになるのでうまくいきませんでした
というわけで作ってみたのが int の Index をもとに 対応する DataTemplate を選択する Selector です
<Page.Resources> <s:IndexToTemplateSelector x:Key="IndexToTemplateSelector"> <s:IndexToTemplateSelector.Templates> <DataTemplate> <Grid> <Viewbox Width="32" Height="32"> <Path Data="F1M-1706.31,-910.775C-1719.92,-906.954 -1724.69,-885.691 -1724.69,-885.691 -1725.26,-889.6 -1728.61,-897.85 -1728.61,-897.85 -1737,-915.8 -1748.87,-909.821 -1748.87,-909.821 -1762.04,-900.802 -1753.21,-884.532 -1753.21,-884.532L-1746.27,-888.586C-1750.61,-895.389 -1747.13,-901.323 -1747.13,-901.323 -1740.91,-907.259 -1735.41,-893.362 -1735.41,-893.362 -1729.77,-885.111 -1728.17,-852.253 -1728.17,-852.253 -1725.28,-850.226 -1720.5,-852.253 -1720.5,-852.253 -1719.34,-899.587 -1705.59,-902.915 -1705.59,-902.915 -1696.33,-903.061 -1702.26,-888.441 -1702.26,-888.441L-1695.75,-884.678C-1686.92,-914.784,-1706.31,-910.775,-1706.31,-910.775" Fill="{Binding Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}" Stretch="Uniform" /> </Viewbox> </Grid> </DataTemplate> <DataTemplate> <Grid> <Viewbox Width="32" Height="32"> <Path Data="F1M-1711.64,-1319.91C-1705.34,-1324.13,-1701.19,-1331.32,-1701.19,-1339.47L-1709.44,-1339.47C-1709.44,-1331.03 -1716.29,-1324.19 -1724.73,-1324.19 -1733.17,-1324.19 -1740.01,-1331.03 -1740.01,-1339.47L-1748.27,-1339.47C-1748.27,-1331.32 -1744.12,-1324.13 -1737.81,-1319.91 -1744.12,-1315.68 -1748.27,-1308.5 -1748.27,-1300.34 -1748.27,-1287.34 -1737.73,-1276.81 -1724.73,-1276.81 -1711.73,-1276.81 -1701.19,-1287.34 -1701.19,-1300.34 -1701.19,-1308.5 -1705.34,-1315.68 -1711.64,-1319.91 M-1724.73,-1285.06C-1733.17,-1285.06 -1740.01,-1291.91 -1740.01,-1300.34 -1740.01,-1308.78 -1733.17,-1315.63 -1724.73,-1315.63 -1716.29,-1315.63 -1709.44,-1308.78 -1709.44,-1300.34 -1709.44,-1291.91 -1716.29,-1285.06 -1724.73,-1285.06" Fill="{Binding Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}" Stretch="Uniform" /> </Viewbox> </Grid> </DataTemplate> <!-- 中略 --> </s:IndexToTemplateSelector.Templates> </s:IndexToTemplateSelector> </Page.Resources>
Templates プロパティに DataTemplate のコレクションを定義しておき、Index が渡されたら対応するコレクション位置の DataTemplate を返すという仕組みです
Path の Fill を外から変更するために TemplateParent の Foreground を Binding しています
/// <summary> /// XAML 定義用 DataTemlate コレクションクラス /// </summary> [ContentProperty()] public class DataTemplateCollection : List<DataTemplate> { } /// <summary> /// Index を DataTemplate に変換する Selector /// </summary> public class IndexToTemplateSelector : DataTemplateSelector { /// <summary> /// テンプレートリスト /// </summary> public DataTemplateCollection Templates { get; private set; } /// <summary> /// コンストラクタ /// </summary> public IndexToTemplateSelector() : base() { this.Templates = new DataTemplateCollection(); } /// <summary> /// Index から対応する DataTemplate を返却します /// </summary> /// <param name="item">int値</param> /// <param name="container">コンテナ</param> /// <returns>DataTemplate</returns> protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) { int index = 0; if (item != null && int.TryParse(item.ToString(), out index) && Templates.Count > index) { return this.Templates[index]; } return null; } }
Selector 本体はこんな感じで記述
Templates プロパティの型は List
<ListView.ItemTemplate> <DataTemplate> <Border Background="White"> <ContentControl HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Content="{Binding}" ContentTemplateSelector="{StaticResource IndexToTemplateSelector}" /> </Border> </DataTemplate> </ListView.ItemTemplate>
アイコンを Flyout 用に並べる部分は ContentControl の Content に Index 値、ContentTemplateSelector に今回作成した Selector を指定すれば大丈夫でした!