しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

WPF メモ (19)

ListBox.ContextMenu に ContextMenu を突っ込むと、各要素*1が ContextMenu の DataContext に入るみたいです。

これに気がつかなかったので、前までは ListBoxItem.ContextMenu にスタイルで指定してたんですが、そんな面倒なことしなくてもよかったみたいです。

ごめんなさい、嘘付いてました。ListBoxItem.ContextMenu に突っ込まないと DataContext が使えないです。

久しぶりにサンプルらしきものを書いてみることにします。ビルドはそのままでは通らないので、雰囲気を感じ取ってください(謎

<ListBox x:Name="listBox">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="ContextMenu">
                <Setter.Value>
                    <ContextMenu>
                        <MenuItem Header="メニューアイテム" IsChecked="{Binding Path=IsEnabled}"/>
                    </ContextMenu>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=Text}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
public class Item
{
    public string Text { get; set; }
    public bool IsEnabled { get; set; }
}

var items = new ObservableCollection<Item>();

items.Add(new Item { Text = "ほげほげ", IsEnabled = false });

listBox.ItemsSource = items;

恐ろしく手抜きなコードなので分かりにくいかと思いますが、ContextMenu を ListBox.ItemContainerStyle 内の Style に突っ込んで、中の MenuItem で DataContext 対象にバインディングの指定をしています。実行するとメニューアイテムは無効になっているはずです。

その下で定義しているデータテンプレートでバインディング出来るのは当たり前なんですが、ContextMenu 内でも Item のインスタンスに対してバインディングが出来るのが不思議*2かつ便利です。選択されているアイテムに対して、動的にメニューの内容を変化させることなどが出来ちゃいます。

*1:ここでは ItemsSource で指定したソースの要素。

*2:個人的にです。