65.9K
CodeProject 正在变化。 阅读更多。
Home

Cheat's Outlook Bar

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (64投票s)

2005年3月3日

4分钟阅读

viewsIcon

225809

downloadIcon

4458

一个替代的“最少代码”Outlook风格菜单栏。

Sample Image - CheatsOutlookBar.jpg

引言

我相信有句老话:“衣着决定一个人”,这句话同样适用于软件。无论您的应用程序多么聪明和勤奋,如果它们没有穿上最新、设计精良的外衣,人们就会认为它们写得很差、过时了。

最近在一个新项目上工作时,我快速搜索了一下网络,想看看竞争对手在做什么。他们有一个功能,而我没有,那就是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 都会移到最底部,但它们的顺序反了,如下所示:

All is not well...

为了纠正这个问题,我尝试了几种方法,例如反向遍历面板的控件,以及“实时”更改 `TabIndex` 值,但都没有成功。我决定在MSDN上研究 `Dock` 属性,它告诉我关于 *z-order* 的信息,并解释说可以通过控件的 `SendToBack` 和 `BringToFront` 方法来控制它。它在这里解释,以及在这里解释,比我用几个词能说清楚得多。总之,通过在每个按钮停靠后调用 `SendToBack` 方法,我保持了按钮的顺序。

最后...

最后一块拼图是另一个标准的Windows控件,`ListView`。我将它添加到容器面板中,将其 `View` 属性保留为默认的 `LargeIcon`,并将其 `Dock` 属性设置为 `Fill`,这意味着它将填充按钮留下的所有可用空间。我添加了一些 `ImageList`,然后用代码填充 `ListView`,使其根据点击的按钮显示不同的内容,这样就得到了一个外观漂亮、功能齐全的Outlook栏,它由标准控件和几行代码构成。然后我添加了第二个 `ListView` 来提供一些基本功能,以证明菜单栏有效。

希望这篇文章能引起您的兴趣,并可能表明有时在开始编写代码之前,从不同的角度看待问题会很有用!

© . All rights reserved.