我正在制作一个 Web 浏览器,但我不知道如何在其 ContextMenuStrip 顶部添加这些按钮:
分隔符为所有项目创建列,但只为一行创建列。
你知道怎么做吗?
Here's a custom Component, inheriting ToolStripControlHost (as the .Net's ToolStripTextBox, ToolStripComboBox etc.) that hosts an UserControl instead of a standard Control.
▶ Building an UserControl, you can add whatever other Controls to its surface and manage their actions as usual, except the UserControl's Events are exposed through the ToolStripControlHost
derived object, so implementers don't need to know anything about the underlying hosted Control.
The hosted Control's events that you want to expose are subscribe to overriding OnSubscribeControlEvents() (and of course unsubscribed to overriding OnUnsubscribeControlEvents), then raising a related or composed event that returns values as needed.
▶ This is shown in the ToolStripControlHost
class, see the public event EventHandler<UserActionArgs> ButtonAction
event, an event that returns a custom EventArgs
argument that includes elements that are needed to determine the action performed by the Button clicked.
When needed, the hosted Control is exposed through the ToolStripControlHost.Control property.
You can initialize an existing ContextMenuStrip (contextMenuStrip1
, here) in the constructor of the Form that uses it:
public partial class Form1 : Form
{
private ToolStripUserControl toolStripUC = new ToolStripUserControl();
public Form1()
{
InitializeComponent();
// Assigns an existing ContextMenuStrip, to the Form or any other Control
this.ContextMenuStrip = contextMenuStrip1;
// Inserts the ToolStripUserControl and a Separator
contextMenuStrip1.Items.Insert(0, new ToolStripSeparator());
contextMenuStrip1.Items.Insert(0, toolStripUC);
// Subscribes to the ButtonAction event
toolStripUC.ButtonAction += (s, e)
=> { this.Text = $"Your Action is {e.UserAction}, triggered by {e.TriggerControl.Name}"; };
contextMenuStrip1.Closed += (s, e) => this.Text = "Right-Click on me";
}
}
ToolStripControlHost
derived class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
[ToolboxItem(false)]
public class ToolStripUserControl : ToolStripControlHost
{
// Pass the UserControl, MenuStripNavigationBar, to the base class.
public ToolStripUserControl() : base(new MenuStripNavigationBar()) { }
public MenuStripNavigationBar NavigatorBar => Control as MenuStripNavigationBar;
// Exposes the ButtonActions Dictionary, to redefine the Buttons' actions
public Dictionary<Control, ButtonAction> ButtonActions {
get => NavigatorBar.ButtonActions;
set => NavigatorBar.ButtonActions = value;
}
// Subscribe to the events you want to expose...
protected override void OnSubscribeControlEvents(Control ctl)
{
base.OnSubscribeControlEvents(ctl);
var navigatorBar = (MenuStripNavigationBar)ctl;
navigatorBar.UserAction += OnButtonAction;
}
// ...and then unsubscribe. This is called when the Form is destroyed
protected override void OnUnsubscribeControlEvents(Control ctl)
{
base.OnUnsubscribeControlEvents(ctl);
var navigatorBar = (MenuStripNavigationBar)ctl;
navigatorBar.UserAction -= OnButtonAction;
}
// Exposes a public custom event
public event EventHandler<UserActionArgs> ButtonAction;
// Raises the event when an UserAction is triggered
private void OnButtonAction(object sender, EventArgs e)
{
var ctl = sender as Control;
var userAction = new UserActionArgs(ButtonActions[ctl], ctl);
ButtonAction?.Invoke(this, userAction);
}
}
Custom EventArgs object:
public class UserActionArgs : EventArgs
{
public UserActionArgs(ButtonAction action, Control control)
{
this.UserAction = action;
this.TriggerControl = control;
}
public ButtonAction UserAction { get; }
public Control TriggerControl { get; }
}
Actions enumerator:
public enum ButtonAction
{
MoveBack,
MoveForward,
PlayMusic,
PlayAnimation
}
This is how it works:
This is the full UserControl, to ease testing:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
public partial class MenuStripNavigationBar : UserControl
{
public event EventHandler UserAction;
public MenuStripNavigationBar()
{
InitializeComponent();
this.ButtonActions = new Dictionary<Control, ButtonAction>();
this.buttonArrowLeft.Text = "⏪";
ButtonActions.Add(this.buttonArrowLeft, ButtonAction.MoveBack);
this.buttonArrowLeft.Click += ButtonsActionEvent;
this.buttonArrowRight.Text = "⏩";
ButtonActions.Add(this.buttonArrowRight, ButtonAction.MoveBack);
this.buttonArrowRight.Click += ButtonsActionEvent;
this.buttonMusicKey.Text = "♬";
ButtonActions.Add(this.buttonMusicKey, ButtonAction.PlayMusic);
this.buttonMusicKey.Click += ButtonsActionEvent;
this.buttonAction.Text = "⛄";
ButtonActions.Add(this.buttonAction, ButtonAction.PlayAnimation);
this.buttonAction.Click += ButtonsActionEvent;
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Dictionary<Control, ButtonAction> ButtonActions { get; set; }
private void ButtonsActionEvent(object sender, EventArgs e)
=> UserAction?.Invoke(sender, e);
[ToolboxItem(false)]
internal class ButtonPanel : Panel
{
private Color borderActiveColor = Color.LightSteelBlue;
private Color borderInactiveColor = Color.Gray;
private Color borderColor = Color.Transparent;
public ButtonPanel()
{
this.SetStyle(ControlStyles.Selectable | ControlStyles.SupportsTransparentBackColor |
ControlStyles.UserMouse | ControlStyles.StandardClick, true);
this.UpdateStyles();
this.BackColor = Color.Transparent;
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
this.OnEnter(e);
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
this.OnLeave(e);
}
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
bool hovered = this.ClientRectangle.Contains(this.PointToClient(MousePosition));
borderColor = hovered ? Enabled ? borderActiveColor : borderInactiveColor : Color.Transparent;
this.Invalidate();
}
protected override void OnLeave(EventArgs e)
{
if (this.ClientRectangle.Contains(this.PointToClient(MousePosition))) return;
borderColor = Color.Transparent;
base.OnLeave(e);
this.Invalidate();
}
TextFormatFlags flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter |
TextFormatFlags.NoPadding | TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.SingleLine;
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var textRect = Rectangle.Inflate(ClientRectangle, 0, -1);
TextRenderer.DrawText(e.Graphics, Text, Font, textRect, ForeColor, Color.Empty, flags);
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, borderColor, ButtonBorderStyle.Solid);
}
}
}
Designer file:
partial class MenuStripNavigationBar
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.buttonAction = new MenuStripNavigationBar.ButtonPanel();
this.buttonArrowLeft = new MenuStripNavigationBar.ButtonPanel();
this.buttonArrowRight = new MenuStripNavigationBar.ButtonPanel();
this.buttonMusicKey = new MenuStripNavigationBar.ButtonPanel();
this.SuspendLayout();
//
// buttonAction
//
this.buttonAction.BackColor = System.Drawing.Color.Transparent;
this.buttonAction.Font = new System.Drawing.Font("Segoe UI Symbol", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonAction.Location = new System.Drawing.Point(166, 2);
this.buttonAction.Name = "buttonAction";
this.buttonAction.Size = new System.Drawing.Size(42, 26);
this.buttonAction.TabIndex = 0;
//
// buttonArrowLeft
//
this.buttonArrowLeft.BackColor = System.Drawing.Color.Transparent;
this.buttonArrowLeft.Font = new System.Drawing.Font("Segoe UI Symbol", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonArrowLeft.Location = new System.Drawing.Point(3, 2);
this.buttonArrowLeft.Name = "buttonArrowLeft";
this.buttonArrowLeft.Size = new System.Drawing.Size(42, 26);
this.buttonArrowLeft.TabIndex = 0;
//
// buttonArrowRight
//
this.buttonArrowRight.BackColor = System.Drawing.Color.Transparent;
this.buttonArrowRight.Font = new System.Drawing.Font("Segoe UI Symbol", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonArrowRight.Location = new System.Drawing.Point(58, 2);
this.buttonArrowRight.Name = "buttonArrowRight";
this.buttonArrowRight.Size = new System.Drawing.Size(42, 26);
this.buttonArrowRight.TabIndex = 0;
//
// buttonMusicKey
//
this.buttonMusicKey.BackColor = System.Drawing.Color.Transparent;
this.buttonMusicKey.Font = new System.Drawing.Font("Segoe UI Symbol", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.buttonMusicKey.Location = new System.Drawing.Point(112, 2);
this.buttonMusicKey.Name = "buttonMusicKey";
this.buttonMusicKey.Size = new System.Drawing.Size(42, 26);
this.buttonMusicKey.TabIndex = 0;
//
// MenuStripNavigationBar
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
this.BackColor = System.Drawing.Color.Transparent;
this.Controls.Add(this.buttonMusicKey);
this.Controls.Add(this.buttonArrowRight);
this.Controls.Add(this.buttonArrowLeft);
this.Controls.Add(this.buttonAction);
this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.MaximumSize = new System.Drawing.Size(212, 30);
this.MinimumSize = new System.Drawing.Size(212, 30);
this.Name = "MenuStripNavigationBar";
this.Size = new System.Drawing.Size(212, 30);
this.ResumeLayout(false);
}
private ButtonPanel buttonAction;
private ButtonPanel buttonArrowLeft;
private ButtonPanel buttonArrowRight;
private ButtonPanel buttonMusicKey;
}