私はStenのアプローチ、つまりボタンを別のボタンの中にネストするというアプローチを採用しました。ユーザーコントロールを使用して再利用可能にし、すべての要素をコントロールテンプレートに配置して、ボタン内に任意のコンテンツを配置できるようにしました。
<UserControl
x:Class="VidCoder.Controls.SplitButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Loaded="SplitButton_OnLoaded">
<UserControl.Template>
<ControlTemplate TargetType="{x:Type UserControl}">
<Button
HorizontalAlignment="Left" VerticalAlignment="Top" Name="mainButton" ContextMenuService.Placement="Bottom"
Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Button.Content>
<StackPanel Orientation="Horizontal" UseLayoutRounding="True">
<ContentPresenter Margin="{TemplateBinding Padding}" />
<Rectangle Width="1" Fill="#111111" Margin="0,2" />
<Button Click="OnArrowClick">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent" Name="buttonGrid">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Button.Template>
<Button.Content>
<Path Data="M 0,0 L 8,0 L 4,4 Z" Fill="{TemplateBinding Foreground}" Margin="4 0 3 0" VerticalAlignment="Center"/>
</Button.Content>
</Button>
</StackPanel>
</Button.Content>
<Button.ContextMenu>
<ContextMenu Name="buttonMenu" ItemsSource="{Binding Path=MenuItemsSource, RelativeSource={RelativeSource TemplatedParent}}" />
</Button.ContextMenu>
</Button>
</ControlTemplate>
</UserControl.Template>
</UserControl>
コードビハインドは、メニュー項目コレクションとCommandプロパティを公開します。
public partial class SplitButton : UserControl
{
private Button button;
private ObservableCollection<object> menuItemsSource = new ObservableCollection<object>();
public Collection<object> MenuItemsSource { get { return this.menuItemsSource; } }
public SplitButton()
{
InitializeComponent();
}
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command",
typeof (ICommand),
typeof (SplitButton),
new UIPropertyMetadata(null, OnCommandChanged));
public ICommand Command
{
get
{
return (ICommand) GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
private static void OnCommandChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
{
if (eventArgs.NewValue != eventArgs.OldValue)
{
var splitButton = dependencyObject as SplitButton;
if (splitButton.button != null)
{
splitButton.button.Command = eventArgs.NewValue as ICommand;
}
}
}
private void OnArrowClick(object sender, RoutedEventArgs e)
{
var buttonMenu = ContextMenuService.GetContextMenu(this.button);
if (this.menuItemsSource.Count > 0 && buttonMenu != null)
{
buttonMenu.IsOpen = !buttonMenu.IsOpen;
buttonMenu.PlacementTarget = this.button;
buttonMenu.Placement = PlacementMode.Bottom;
}
}
private void SplitButton_OnLoaded(object sender, RoutedEventArgs e)
{
this.button = this.Template.FindName("mainButton", this) as Button;
if (this.Command != null)
{
this.button.Command = this.Command;
}
}
}
使用中で:
<controls:SplitButton HorizontalAlignment="Left" VerticalAlignment="Top" Command="{Binding TestCommand}">
<controls:SplitButton.MenuItemsSource>
<MenuItem Header="ham" Command="{Binding TestCommand2}" />
<MenuItem Header="sandwiches" />
<MenuItem Header="yum" />
</controls:SplitButton.MenuItemsSource>
<TextBlock Padding="4" Text="Testing" />
</controls:SplitButton>