C# 带有下拉菜单的 Windows.Forms 按钮
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10803184/
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
Windows.Forms button with drop-down menu
提问by tonytony
I'm developing simple C# application using Windows.Forms on .NET. I need some button that will show a drop-down menu with subcategories - much like ToolStripMenu, but the button, you know. I searched for it and could not found any variants.
我正在 .NET 上使用 Windows.Forms 开发简单的 C# 应用程序。我需要一些按钮来显示带有子类别的下拉菜单 - 很像 ToolStripMenu,但是按钮,你知道。我搜索了它,但找不到任何变体。
My question is: is there any way to do this, maybe some secret button property that allows attach menu to it?
我的问题是:有没有办法做到这一点,也许是一些允许附加菜单的秘密按钮属性?
Any help will be appreciated.
任何帮助将不胜感激。
采纳答案by LarsTech
You can show the ContextMenuStrip on the click event:
您可以在单击事件上显示 ContextMenuStrip:
private void button1_Click(object sender, EventArgs e) {
contextMenuStrip1.Show(button1, new Point(0, button1.Height));
}
To make your own determination whether to show the menu above or below the button, you can try using this code, which measures the menu and determines whether or not it would be partially offscreen:
要自己决定是在按钮上方还是下方显示菜单,您可以尝试使用以下代码,该代码测量菜单并确定它是否部分离屏:
private void button1_Click(object sender, EventArgs e) {
Point screenPoint = button1.PointToScreen(new Point(button1.Left, button1.Bottom));
if (screenPoint.Y + contextMenuStrip1.Size.Height > Screen.PrimaryScreen.WorkingArea.Height) {
contextMenuStrip1.Show(button1, new Point(0, -contextMenuStrip1.Size.Height));
} else {
contextMenuStrip1.Show(button1, new Point(0, button1.Height));
}
}
回答by clearpath
Show context menu below button when it's clicked.
单击时在按钮下方显示上下文菜单。
回答by JoshL
The simplest option would be to use the ToolStripDropDownButton in an undocked ToolStrip that only shows the single button. Then you can add sub-items to it, etc. To do this: - drag a Toolstrip onto your control/form - use the layout helper to add a DropDownButton - set GripStyle to Hidden - set Dock to None
最简单的选择是在仅显示单个按钮的未停靠 ToolStrip 中使用 ToolStripDropDownButton。然后你可以向它添加子项目,等等。要做到这一点: - 将工具条拖到你的控件/表单上 - 使用布局助手添加一个 DropDownButton - 将 GripStyle 设置为隐藏 - 将 Dock 设置为无
The result is a standalone toolbar-style button that supports the drop-down behavior that you described.
结果是一个独立的工具栏样式按钮,支持您描述的下拉行为。
回答by roken
Infragistics has the WinDropDownButton: http://help.infragistics.com/Help/NetAdvantage/WinForms/2012.1/CLR2.0/html/WinDropDownButton_About_WinDropDownButton.html
Infragistics 有 WinDropDownButton:http://help.infragistics.com/Help/NetAdvantage/WinForms/2012.1/CLR2.0/html/WinDropDownButton_About_WinDropDownButton.html
So it certainly exists, however you may not be looking for a paid third-party control.
所以它肯定存在,但是您可能不是在寻找付费的第三方控件。
回答by Jaex
Button have down arrow right side of it and you can set menu of it from designer:
按钮右侧有向下箭头,您可以从设计器中设置它的菜单:


With ShowMenuUnderCursor:
使用 ShowMenuUnderCursor:


MenuButton class:
菜单按钮类:
public class MenuButton : Button
{
[DefaultValue(null)]
public ContextMenuStrip Menu { get; set; }
[DefaultValue(false)]
public bool ShowMenuUnderCursor { get; set; }
protected override void OnMouseDown(MouseEventArgs mevent)
{
base.OnMouseDown(mevent);
if (Menu != null && mevent.Button == MouseButtons.Left)
{
Point menuLocation;
if (ShowMenuUnderCursor)
{
menuLocation = mevent.Location;
}
else
{
menuLocation = new Point(0, Height);
}
Menu.Show(this, menuLocation);
}
}
protected override void OnPaint(PaintEventArgs pevent)
{
base.OnPaint(pevent);
if (Menu != null)
{
int arrowX = ClientRectangle.Width - 14;
int arrowY = ClientRectangle.Height / 2 - 1;
Brush brush = Enabled ? SystemBrushes.ControlText : SystemBrushes.ControlDark;
Point[] arrows = new Point[] { new Point(arrowX, arrowY), new Point(arrowX + 7, arrowY), new Point(arrowX + 3, arrowY + 4) };
pevent.Graphics.FillPolygon(brush, arrows);
}
}
}
回答by Mou
easy was we can do it. this may help :)
很简单,我们可以做到。这可能会有所帮助:)
ContextMenuStrip contextMenuStrip1 = new ContextMenuStrip();
private void button1_Click(object sender, EventArgs e)
{
contextMenuStrip1.Items.Clear();
contextMenuStrip1.Items.Add("item1");
contextMenuStrip1.Items.Add("item2");
contextMenuStrip1.Show(button1, new Point(0, button1.Height));
}
private void contextMenuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
if (e.ClickedItem.Text == "item1")
{
MessageBox.Show(e.ClickedItem.Text);
}
}
回答by Sverrir Sigmundarson
Expanding @Jaex answera little bit to allow for a separator line, conditional drawing of the arrow if nothing is configured and a separate click event for the main button body and the menu arrow.
稍微扩展@Jaex 答案以允许分隔线、在未配置任何内容的情况下有条件地绘制箭头以及主按钮主体和菜单箭头的单独单击事件。
It should be noted that for better alignment you can set the button.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
需要注意的是,为了更好的对齐,您可以设置 button.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
Here is my slight improvement
这是我的轻微改进
public class SplitButton : Button
{
[DefaultValue(null), Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public ContextMenuStrip Menu { get; set; }
[DefaultValue(20), Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int SplitWidth { get; set; }
public SplitButton()
{
SplitWidth = 20;
}
protected override void OnMouseDown(MouseEventArgs mevent)
{
var splitRect = new Rectangle(this.Width - this.SplitWidth, 0, this.SplitWidth, this.Height);
// Figure out if the button click was on the button itself or the menu split
if (Menu != null &&
mevent.Button == MouseButtons.Left &&
splitRect.Contains(mevent.Location) )
{
Menu.Show(this, 0, this.Height); // Shows menu under button
//Menu.Show(this, mevent.Location); // Shows menu at click location
}
else
{
base.OnMouseDown(mevent);
}
}
protected override void OnPaint(PaintEventArgs pevent)
{
base.OnPaint(pevent);
if (this.Menu != null && this.SplitWidth > 0)
{
// Draw the arrow glyph on the right side of the button
int arrowX = ClientRectangle.Width - 14;
int arrowY = ClientRectangle.Height / 2 - 1;
var arrowBrush = Enabled ? SystemBrushes.ControlText : SystemBrushes.ButtonShadow;
var arrows = new[] { new Point(arrowX, arrowY), new Point(arrowX + 7, arrowY), new Point(arrowX + 3, arrowY + 4) };
pevent.Graphics.FillPolygon(arrowBrush, arrows);
// Draw a dashed separator on the left of the arrow
int lineX = ClientRectangle.Width - this.SplitWidth;
int lineYFrom = arrowY - 4;
int lineYTo = arrowY + 8;
using( var separatorPen = new Pen(Brushes.DarkGray){DashStyle = DashStyle.Dot})
{
pevent.Graphics.DrawLine(separatorPen, lineX, lineYFrom, lineX, lineYTo);
}
}
}
}
回答by Jeff Scott
Jaex's MenuButton class above was perfect for me. I did add the logic below into the OnMouseDown so that the context menu would only show up if I clicked on the arrow. The normal click event would get triggered if I clicked in the larger portion. Allowed for a "Default" click action.
上面 Jaex 的 MenuButton 类对我来说是完美的。我确实将下面的逻辑添加到 OnMouseDown 中,以便只有在我单击箭头时才会显示上下文菜单。如果我单击较大的部分,则会触发正常的单击事件。允许“默认”点击操作。
if (Menu != null && mevent.Button == MouseButtons.Left)
{
if (mevent.Location.X >= this.Width - 14)
{
System.Drawing.Point menuLocation;
if (ShowMenuUnderCursor)
{
menuLocation = mevent.Location;
}
else
{
menuLocation = new System.Drawing.Point(0, Height);
}
Menu.Show(this, menuLocation);
}
}
Thought this might be useful to someone. Thanks Jaex
认为这可能对某人有用。谢谢Hyman斯
回答by Bart Friederichs
I was fiddling with this issue as well and found an extremely simple solution (albeit a little dirty-hacky): place a ComboBoxunder the Button, such that it shows the dropdown arrow right next to the button.
我也在摆弄这个问题,并找到了一个非常简单的解决方案(虽然有点脏):在ComboBox下放置一个Button,这样它就会在按钮旁边显示下拉箭头。
Then use SelectedIndexChangedof the ComboBoxto change the Buttonbehaviour, or do what you want it to do immediately.
然后使用SelectedIndexChanged的ComboBox改变Button行为,或者你要立即做什么。

