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!!
谢谢!!
4 个解决方案
#1
32
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:
您可以使用附加属性或行为来实现下拉按钮功能,而不是使用子类化按钮,以实现更类似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.
当前的要点和示例。
#2
8
i found this two solutions after searching for it:
我在搜索后找到了这两个解决方案:
1)WPF中的分割按钮
2)WPF中的DropDownButtons
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...
希望能帮到你......
#3
8
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:
如果你有足够的目标.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>
#4
1
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
.
这会将您的按钮包装到具有子菜单的MenuItem中。如此处所示,名为IsSubMenuOpen的MenuItem属性绑定到ViewModel中名为SomeProperty的bool类型的通知属性。
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中连接其他行为。
#1
32
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:
您可以使用附加属性或行为来实现下拉按钮功能,而不是使用子类化按钮,以实现更类似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.
当前的要点和示例。
#2
8
i found this two solutions after searching for it:
我在搜索后找到了这两个解决方案:
1)WPF中的分割按钮
2)WPF中的DropDownButtons
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...
希望能帮到你......
#3
8
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:
如果你有足够的目标.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>
#4
1
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
.
这会将您的按钮包装到具有子菜单的MenuItem中。如此处所示,名为IsSubMenuOpen的MenuItem属性绑定到ViewModel中名为SomeProperty的bool类型的通知属性。
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中连接其他行为。