我正在开发一个 C# WinForms 应用程序,其中有许多进程,这些进程全部由“主”应用程序管理。 在此主应用程序中,每个进程都通过其自己的
FlowLayoutPanel
进行可视化,其中包含许多用于各种功能的按钮。我将这些面板称为“流程块”。
然而,当完成许多这样的过程时,并不是所有的块都能轻松地显示在屏幕上。因此,我正在实现“紧凑模式”,它隐藏所有进程块的所有按钮,只留下它们的名称、状态和开始/停止按钮可见。然后,我为每个进程块分配一个
ContextMenuStrip
,其中显示列为 ToolStripMenuItem
的所有按钮,以便我可以通过这种方式访问进程块的所有功能。我正在动态清除这些 ContextMenuStrip
并在打开菜单时添加项目。
为此,我迭代 FlowLayoutPanel
的所有子控件,查看它们是否属于 Button
类型,如果是,则将它们添加到 ContextMenuStrip
中。请参阅下面的代码片段:
private void PanelCmsOpened(object sender, EventArgs e) {
try {
ContextMenuStrip cMenuStrip = (ContextMenuStrip) sender;
// Clear all items from the context menu
cMenuStrip.Items.Clear();
// Loop over all controls in the FlowLayoutPanel
foreach (var c in CPanel.Controls) {
Button btn = c as Button;
if (btn == null) continue; // Not a button, continue
// Get the text from the button
string lbl = btn.Text;
if (string.IsNullOrEmpty(lbl)) {
try {
// The button has no text (only an icon), so we get the tooltip text of the button
lbl = PanelTooltip.GetToolTip(btn);
}
catch {
// We can't get any text to display, so skip this button
continue;
}
}
// Add a new item to the ContextMenuStrip
cMenuStrip.Items.Add(new ToolStripMenuItem(lbl,
btn.BackgroundImage,
(s, ea) => btn.PerformClick() // Perform a click on the button
)
{
Enabled = btn.Enabled
});
}
}
catch (Exception Ex) {
MessageBox.Show("Fout bij openen van context menu: " + Ex.Message, "Fout", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
问题: 现在,只要按钮可见,就一切正常。但是,当进入紧凑模式时,我通过设置按钮的
Button.Visible
属性来隐藏按钮。在这种情况下,什么也不会发生。我尝试在 PerformClick
周围放置一个 try-catch 块,但没有抛出异常。只是什么也没发生。有谁知道如何使其适用于隐藏按钮?
PerformClick
在执行单击之前检查按钮是否可供单击。隐藏按钮被视为不可用。您可以简单地在执行单击之前显示按钮,并在单击后隐藏它:
cMenuStrip.Items.Add(
new ToolStripMenuItem(lbl, btn.BackgroundImage, (s, ea) => {
var size = btn.Size;
btn.Size = Size.Empty; // button still will be invisible
btn.Show(); // make it clickable
btn.PerformClick();
btn.Hide(); // hide again
btn.Size = size; // restore original size
});
注意:如果你还需要添加一些可见的按钮,那么你应该单独处理它们,以避免闪烁
cMenuStrip.Items.Add(new ToolStripMenuItem(
lbl, btn.BackgroundImage, (s, ea) => ClickButton(btn)));
其中
ClickButton
是一种根据按钮是否可见执行不同逻辑的方法:
private void ClickButton(Button button)
{
if (button.Visible)
{
button.PerformClick();
return;
}
var size = button.Size;
button.Size = Size.Empty;
button.Show();
button.PerformClick();
button.Hide();
button.Size = size;
}
唯一不能做的就是设置
visible = false;
除此之外,你可以使用任何技巧来隐藏按钮:你可以将它们堆叠在另一个控件后面,你可以将它们从任何方向移出视线,甚至将它们移动到不同的父控件中:
隐藏它们:
panel1.Size = Size.Empty;
button1.Parent = panel1;
//..
再次向他们展示:
button1.Parent = this;
//..
假设他们坐在表格上。
请注意,它们将保留原来的位置和尺寸;注意 tab 顺序和 z 顺序的变化!
如果按钮不可见,则不会引发 Click 事件。 一种选择是获取按钮单击事件中的代码并将其添加为单独的方法。然后调用该方法而不是 PerformClick 行。如果您在每次单击按钮时都执行相同的操作,那么这将起作用。
另一个选项是使按钮透明。这将使它们对客户端不可见,并且 PerformClick 事件将正常工作。您可以在以下链接中看到:绘制透明按钮。
希望这有帮助。
实现这个方法:
private void InvokeButtonClick(Button button)
{
var clickEvent = button.GetType().GetMethod("OnClick", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
clickEvent.Invoke(button, new object[] { EventArgs.Empty });
}