読者です 読者をやめる 読者になる 読者になる

DropDownButton を実装する添付ビヘイビア

私が WPF で不満に思っていることの1つに、「DropDownButton が無い」があります。過去に何回かこの話題を記事にしていますが、それくらい私にとっては大問題です。Windows Forms の ToolStripDropDownButton みたいなコントロールが、なんで WPF には無いのかと小一時間。


一応、ToggleButton と ContextMenu を使えばそれっぽく実装できます。ToggleButton がチェック状態のときに ContextMenu を表示してやればいいです。ただ、これ毎回実装するの面倒。


実装を使い回したいけど、DropDownButton コントロールを自作するのもなんかイヤです。「いつか標準で提供されるかも…」という淡い期待が邪魔をして、自作する気にはなりません。テンプレート書くの大変なんだもの。


よろしい、ならば添付ビヘイビアだ。


ということで、ToggleButton を DropDownButton 化する添付ビヘイビア作ってみました。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;

namespace DropDownButtonSample
{
    public static class DropDownMenuBehavior
    {
        public static readonly DependencyProperty DropDownMenuProperty = DependencyProperty.RegisterAttached(
            "DropDownMenu",
            typeof(ContextMenu),
            typeof(DropDownMenuBehavior),
            new PropertyMetadata(null, OnDropDownMenuChanged));

        private static void OnDropDownMenuChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var button = sender as ToggleButton;
            if (button == null)
            {
                return;
            }

            var dropDownMenu = e.NewValue as ContextMenu;
            if (dropDownMenu == null)
            {
                return;
            }

            dropDownMenu.Placement = PlacementMode.Bottom;
            dropDownMenu.PlacementTarget = button;
            button.SetBinding(ToggleButton.IsCheckedProperty, new Binding("IsOpen")
            {
                Source = dropDownMenu,
            });
        }

        public static void SetDropDownMenu(ToggleButton button, ContextMenu dropDownMenu)
        {
            button.SetValue(DropDownMenuProperty, dropDownMenu);
        }

        public static ContextMenu GetDropDownMenu(ToggleButton button)
        {
            return button.GetValue(DropDownMenuProperty) as ContextMenu;
        }
    }
}

こんな風に使います。

<Window x:Class="DropDownButtonSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DropDownButtonSample"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel LastChildFill="False">
        <ToolBar DockPanel.Dock="Top">
            <ToggleButton Content="操作">
                <local:DropDownMenuBehavior.DropDownMenu>
                    <ContextMenu>
                        <MenuItem Header="開く"/>
                    </ContextMenu>
                </local:DropDownMenuBehavior.DropDownMenu>
            </ToggleButton>
        </ToolBar>
    </DockPanel>
</Window>

実行結果がこちら。
f:id:griefworker:20101001201206j:image

それっぽく動いたので満足です。


自作コントロールだったら、ツールバー内に配置したときのデザインとか考える必要があります。その点、添付ビヘイビアなら ToggleButton をそのまま使うので、ツールバー専用のテンプレートは不要。自作コントロールに比べて、はるかに手間が少なくて済みます。


ホント、添付ビヘイビアって便利。