Cheat's Outlook Bar






4.88/5 (64投票s)
2005年3月3日
4分钟阅读

225809

4458
一个替代的“最少代码”Outlook风格菜单栏。
引言
我相信有句老话:“衣着决定一个人”,这句话同样适用于软件。无论您的应用程序多么聪明和勤奋,如果它们没有穿上最新、设计精良的外衣,人们就会认为它们写得很差、过时了。
最近在一个新项目上工作时,我快速搜索了一下网络,想看看竞争对手在做什么。他们有一个功能,而我没有,那就是Outlook风格的菜单栏,通常简称为Outlook栏。我想拥有一个,就考虑自己写。在Code Project上搜索,我找到了两篇有用的文章:Marc Clifton的《An Outlook Bar Implementation》和ACorbs的《Outlook XP bar》。这两篇文章都很有趣,发人深省,我下载了它们,像平常一样仔细研究了一番!
然后我陷入了两难。我不想简单地复制别人的代码,但同时,我也不想花大量时间重新发明轮子。我记得多年前我以前的老板说过一句话:“我们在这里要做什么?是追求技术卓越,还是完成工作?”意识到Marc和ACorbs已经做了前者,我决定采取后者的方法,并开始进行横向思考。
灵感闪现!
我开始在标准的Windows Forms工具箱里翻找,并开始随意地摆弄分隔器和面板。在此过程中,我遇到了 `Dock` 属性,它指定了控件的 *对齐方式*。换句话说,它是附着在容器的顶部、底部、左侧还是右侧,还是填充所有可用空间。一个想法闪过,我向我的窗体添加了一个 `Panel`,并在面板中添加了三个 `Button`。我将每个按钮的 `Dock` 属性设置为 `Top`,然后,“看!”,我创建了一个Outlook栏!
好吧,差不多……
显然,我实际上只是一叠三个按钮,但它们确实会随着面板一起调整大小,这挺不错的。这时,我意识到我必须写一些代码。
一些代码
我真正需要的所有代码都在按钮的 `Click` 事件处理程序中。它们共享一个通用的处理程序,如下所示:
void ButtonClick(object sender, System.EventArgs e)
{
// Get the clicked button...
Button clickedButton = (Button)sender;
// ... and it's tabindex
int clickedButtonTabIndex = clickedButton.TabIndex;
// Send each button to top or bottom as appropriate
foreach (Control ctl in panel1.Controls)
{
if (ctl is Button)
{
Button btn = (Button)ctl;
if (btn.TabIndex > clickedButtonTabIndex)
{
if (btn.Dock != DockStyle.Bottom)
{
btn.Dock = DockStyle.Bottom;
// This is vital to preserve the correct order
btn.BringToFront();
}
}
else
{
if (btn.Dock != DockStyle.Top)
{
btn.Dock = DockStyle.Top;
// This is vital to preserve the correct order
btn.BringToFront();
}
}
}
}
// Determine which button was clicked.
switch (clickedButton.Text)
{
case "Cars":
CreateCarList();
break;
case "Outlook Shortcuts":
CreateOutlookList();
break;
case "Zip Files":
CreateZipList();
break;
case "Miscellaneous":
CreateMiscList();
break;
}
// Without this, the buttons will hide the items.
listView1.BringToFront();
}
基本上,当面板上的任何一个按钮被点击时,我们都会保存被点击的按钮及其 `TabIndex`,然后依次遍历面板上的所有控件。如果是一个按钮,我们就将 `TabIndex` 与被点击的按钮进行比较。如果 `TabIndex` 更大,那么当前按钮就应该在被点击的按钮下方,所以我们通过将其 `Dock` 设置为 `DockStyle.Bottom` 来将其移到最底部。如果 `TabIndex` 更小,那么按钮就移到顶部。
在这个阶段,我应该指出,为了使它正常工作,按钮的 TabIndex 在设计时设置为正确的顺序是至关重要的。在提供的示例中,“Cars”、“Miscellaneous”、“Zip Files”和“Outlook Shortcuts”按钮的 `TabIndex` 分别设置为 1、2、3 和 4。
回到主要情节。将 `Dock` 属性设置为上下移动按钮后,我注意到事情并不顺利。如果我有按钮 1、2、3 和 4 在顶部,并且我点击了按钮 1,那么按钮 2 到 4 都会移到最底部,但它们的顺序反了,如下所示:
为了纠正这个问题,我尝试了几种方法,例如反向遍历面板的控件,以及“实时”更改 `TabIndex` 值,但都没有成功。我决定在MSDN上研究 `Dock` 属性,它告诉我关于 *z-order* 的信息,并解释说可以通过控件的 `SendToBack` 和 `BringToFront` 方法来控制它。它在这里解释,以及在这里解释,比我用几个词能说清楚得多。总之,通过在每个按钮停靠后调用 `SendToBack` 方法,我保持了按钮的顺序。
最后...
最后一块拼图是另一个标准的Windows控件,`ListView`。我将它添加到容器面板中,将其 `View` 属性保留为默认的 `LargeIcon`,并将其 `Dock` 属性设置为 `Fill`,这意味着它将填充按钮留下的所有可用空间。我添加了一些 `ImageList`,然后用代码填充 `ListView`,使其根据点击的按钮显示不同的内容,这样就得到了一个外观漂亮、功能齐全的Outlook栏,它由标准控件和几行代码构成。然后我添加了第二个 `ListView` 来提供一些基本功能,以证明菜单栏有效。
希望这篇文章能引起您的兴趣,并可能表明有时在开始编写代码之前,从不同的角度看待问题会很有用!