wpf 单击按钮时如何打开弹出菜单?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8958946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 23:15:28  来源:igfitidea点击:

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

wpf

提问by Ryan

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!!

谢谢!!

回答by Ryan

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:

Button您可以使用附加属性或行为来实现下拉按钮功能,而不是使用 subclassed ,以获得更类似于 WPF 的方法,因此您不会影响按钮样式:

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.

当前的要点来源和示例在这里

回答by Chris

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

如果您有幸针对 .NET 4 或更新版本,新的 Ribbon 库有一个RibbonMenuButton可以做到这一点。在 4.5 中,就像在项目中引用 System.Windows.Controls.Ribbon 一样简单:

<RibbonMenuButton x:Name="ExampleMenu" SmallImageSource="/Images/Example.png">
    <RibbonMenuItem x:Name="ExampleMenuItem" Header="Save" />
</RibbonMenuButton>

回答by punker76

i found this two solutions after searching for it:

我在搜索后找到了这两个解决方案:

1) Split Button in WPF

1)WPF中的拆分按钮

2) DropDownButtons in WPF

2) WPF 中的下拉按钮

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

第二个解决方案是我最喜欢的(来源来自 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...

希望能帮到你...

回答by Gayot Fow

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 MenuItemthat has a submenu. As shown here, the MenuItemproperty called IsSubMenuOpenis bound to a notifying property of type bool in your ViewModel called SomeProperty.

这会将您的按钮包装成MenuItem具有子菜单的一个。如此处所示,MenuItem调用的属性IsSubMenuOpen绑定到您的 ViewModel 中名为 .bool 的通知属性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.

您必须让 ViewModel 根据您实际尝试执行的操作来切换此属性。您可能需要考虑将您的按钮设为切换按钮,以便于关闭子菜单,否则您必须在 ViewModel 中连接其他行为。