WPF的分割按钮,适用于Win7和Win8主题

时间:2012-12-01 18:05:03

标签: wpf xaml wpf-controls

任何人都知道在Win7主题和Win8主题中看起来像常规按钮的WPF分割按钮?我正在使用一个看起来很适合Win7但在Win8中像拇指一样伸出的拇指:

weird button

我已尝试过WPF Splitbutton project on codeplexBanana Splitbuttonsplitbutton in the Extended WPF Toolkit

那里有什么可以在Win7中提供Win7主题按钮,在Win8中提供Win8主题按钮吗?

我需要控件具有可绑定的Command属性,并在按下向下箭头时显示上下文菜单。

3 个答案:

答案 0 :(得分:2)

我采用了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>

Splitbutton usage example

答案 1 :(得分:1)

你总是可以用两个标准按钮制作你自己的按钮并不是那么难 - 只是按钮内的一个按钮,自定义内部的样式缺少边框,有下拉三角形并且有“透明”背景(与导致点击的{x:null}背景不同)

大概是这样的:

<Button Style="outerStyle">
  <Button.Content>
     <StackPanel Orientation="Horizontal">
        <Label>Click Me</Label>
        <Button Style="{innerStyleWithTransparentBackground}"> ▼ </Button>
     </StackPanel>
  </Button.Content>
</Button>

如果您使用大量拆分按钮(无论如何都可以),您可以将此构造放在具有几个路由事件的用户控件中,否则您可以将其嵌套在其他代码中。

这不是最优雅的解决方案,但它可能是您找到的最简单的解决方案之一。

答案 2 :(得分:0)

“像拇指一样伸出来”是wpf控件如何解决其风格的结果。默认情况下(意味着如果您没有通过Style属性提供Style),splitbutton将在资源树上向上,直到找到TargetType为splitButton的样式和隐式样式x:Key“{x:Type SplitButton} ”。如果找不到拆分按钮的样式,它将在主题文件中查找您当前使用的任何窗口主题。在win7中,这通常是Aero.NormalColor.xaml。我不确定win8但是我想象Metro.NormalColor.xaml(如果我错了,请纠正我)。如果它在主题词典中找不到样式,它将在Generic.xaml中查找。无论如何,你想要做的是在资源树的一个级别定义一个隐含的控件样式(如果它是独立的,可能在Window,如果xaml在浏览器中托管,则可以是Page)。这将是是常用的样式(未明确定义样式时)。

实施例: http://msdn.microsoft.com/en-us/library/ms745683.aspx#styling_basics