How to open a popup menu when a button is clicked?

2020-02-26 04:39发布

I have a button with an Image as its content in a toolbar. I would like this button to open a menu beneath it when clicked. How?

<Toolbar>
            <Button>
                <Button.Content>
                    <Image  Source="../Resources/help.png"></Image>
                </Button.Content>
            </Button>
</Toolbar>

Thanks!!

标签: wpf
4条回答
女痞
2楼-- · 2020-02-26 05:20

i found this two solutions after searching for it:

1) Split Button in WPF

2) DropDownButtons in WPF

the second solution is my favorit (source taken from the website by Andrew Wilkinson)

public class DropDownButton : ToggleButton
{
  // *** Dependency Properties ***

  public static readonly DependencyProperty DropDownProperty =
    DependencyProperty.Register("DropDown",
                                typeof(ContextMenu),
                                typeof(DropDownButton),
                                new UIPropertyMetadata(null));

  // *** Constructors *** 

  public DropDownButton() {
    // Bind the ToogleButton.IsChecked property to the drop-down's IsOpen property 

    Binding binding = new Binding("DropDown.IsOpen");
    binding.Source = this;
    this.SetBinding(IsCheckedProperty, binding);
  }

  // *** Properties *** 

  public ContextMenu DropDown {
    get { return (ContextMenu)this.GetValue(DropDownProperty); }
    set { this.SetValue(DropDownProperty, value); }
  }

  // *** Overridden Methods *** 

  protected override void OnClick() {
    if (this.DropDown != null) {
      // If there is a drop-down assigned to this button, then position and display it 

      this.DropDown.PlacementTarget = this;
      this.DropDown.Placement = PlacementMode.Bottom;

      this.DropDown.IsOpen = true;
    }
  }
}

usage

<ctrl:DropDownButton Content="Drop-Down">
  <ctrl:DropDownButton.DropDown>
    <ContextMenu>
      <MenuItem Header="Item 1" />
      <MenuItem Header="Item 2" />
      <MenuItem Header="Item 3" />
    </ContextMenu>
  </ctrl:DropDownButton.DropDown>
</ctrl:DropDownButton>

hope that helps you...

查看更多
\"骚年 ilove
3楼-- · 2020-02-26 05:21

There are lots of ways to get this done and you might consider this approach...

<ToolBar DockPanel.Dock="Top">
    <MenuItem IsSubmenuOpen="{Binding SomeProperty}">
        <MenuItem.Header>
            <Button Height="28">
                <Button.Content>
                    <Image Source="---your image---"></Image>
                </Button.Content>
            </Button>
        </MenuItem.Header>
        <Menu>
            <MenuItem Header="Do this" />
            <MenuItem Header="Do that"/>
        </Menu>
    </MenuItem>
</ToolBar>

This wraps your button into a MenuItem that has a submenu. As shown here, the MenuItem property called IsSubMenuOpen is bound to a notifying property of type bool in your ViewModel called SomeProperty.

You would have to have your ViewModel toggle this property depending upon what you are actually trying to do. You may want to consider making your button a toggle button so as to facilitate closing the submenu, otherwise you'll have to wire up additional behaviour in your ViewModel.

查看更多
相关推荐>>
4楼-- · 2020-02-26 05:35

If you have the luxury of targeting .NET 4 or newer, the new Ribbon library has a RibbonMenuButton that can do this. In 4.5 it is as easy as referencing System.Windows.Controls.Ribbon in your project:

<RibbonMenuButton x:Name="ExampleMenu" SmallImageSource="/Images/Example.png">
    <RibbonMenuItem x:Name="ExampleMenuItem" Header="Save" />
</RibbonMenuButton>
查看更多
Melony?
5楼-- · 2020-02-26 05:39

Instead of using a subclassed Button, you can use Attached Properties or a Behavior to implement the drop down button functionality, for a more WPF-like approach and so you don't impact the button style:

using System.Windows.Interactivity;

public class DropDownButtonBehavior : Behavior<Button>
{
    private bool isContextMenuOpen;

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.AddHandler(Button.ClickEvent, new RoutedEventHandler(AssociatedObject_Click), true);
    }

    void AssociatedObject_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        Button source = sender as Button;
        if (source != null && source.ContextMenu != null)
        {
            if (!isContextMenuOpen)
            {
                // Add handler to detect when the ContextMenu closes
                source.ContextMenu.AddHandler(ContextMenu.ClosedEvent, new RoutedEventHandler(ContextMenu_Closed), true);
                // If there is a drop-down assigned to this button, then position and display it 
                source.ContextMenu.PlacementTarget = source;
                source.ContextMenu.Placement = PlacementMode.Bottom;
                source.ContextMenu.IsOpen = true;
                isContextMenuOpen = true;
            }
        }            
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.RemoveHandler(Button.ClickEvent, new RoutedEventHandler(AssociatedObject_Click));
    }

    void ContextMenu_Closed(object sender, RoutedEventArgs e)
    {
        isContextMenuOpen = false;
        var contextMenu = sender as ContextMenu;
        if (contextMenu != null)
        {
            contextMenu.RemoveHandler(ContextMenu.ClosedEvent, new RoutedEventHandler(ContextMenu_Closed));
        }
    }
}

Usage:

<!-- NOTE: xmlns:i="schemas.microsoft.com/expression/2010/interactivity‌​" -->
<Button>
    <i:Interaction.Behaviors>
        <local:DropDownButtonBehavior/>
    </i:Interaction.Behaviors>
    <Button.Content>
        <StackPanel Orientation="Horizontal">
            <Image Source="/DropDownButtonExample;component/Assets/add.png" SnapsToDevicePixels="True" Height="16" Width="16" />
            <TextBlock Text="Add"/>
            <Separator Margin="2,0">
                <Separator.LayoutTransform>
                    <TransformGroup>
                        <TransformGroup.Children>
                            <TransformCollection>
                                <RotateTransform Angle="90"/>
                            </TransformCollection>
                        </TransformGroup.Children>
                    </TransformGroup>
                </Separator.LayoutTransform>
            </Separator>
            <Path Margin="2" VerticalAlignment="Center" Width="6" Fill="#FF527DB5" Stretch="Uniform" HorizontalAlignment="Right" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "/>
        </StackPanel>
    </Button.Content>
    <Button.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Attribute"/>
            <MenuItem Header="Setting"/>
            <Separator/>
            <MenuItem Header="Property"/>
        </ContextMenu>
    </Button.ContextMenu>
</Button>

Current gist source and example here.

查看更多
登录 后发表回答