本文介紹了使用C#開發(fā)Office2003風(fēng)格菜單的方法。
本文用到的組件源碼及測(cè)試程序下載地址
僅僅使用一行簡單的程序,你就能夠使你的Windows窗體的所有菜單和上下文菜單具有office2003的菜單外觀。同樣地,你也可以只用一行程序,就能為你的菜單加上漂亮的圖標(biāo)。本文實(shí)現(xiàn)的是一個(gè)具有該功能的組件。如果你想讓你的菜單恢復(fù)原來的外觀,也只須調(diào)用End方法即可。

組件的使用
要正確使用組件,必須先將你的組件加入到工具箱中。然后將該組件從工具箱中拖放放到form窗體中。這時(shí)會(huì)看到你的form的設(shè)計(jì)頁中多出了一個(gè)名為OfficeMenus1的圖標(biāo),說明已經(jīng)將菜單組件加入到了form中。緊接著調(diào)用如下方法:
//開始顯示office 2003菜單
OfficeMenus1.Start( FormName ); 注:FormName為要改變菜單風(fēng)格的窗口名稱。
同樣,你也可以通過調(diào)用如下方法終止菜單的office2003風(fēng)格,使之回到原始外觀:
// 改變菜單的外觀風(fēng)格到原始狀態(tài)
OfficeMenus1.End();
為菜單頂添加圖標(biāo)也很簡單,只須為工程添加一個(gè)ImageList(圖像列表控件),然后將OfficeMenu組件的ImageList屬性更改為你添加的ImageList,使用如下代碼實(shí)現(xiàn):
// 為菜單添加圖像
// OfficeMenus.AddPicture( MenuItem MenuItemToAddPictureTo, int ImageIndex );
OfficeMenus1.ImageList = imageList1;
OfficeMenus1.AddPicture(menuItem2, 1);
可以看出,只須如此幾行代碼就能輕松讓你的菜單實(shí)現(xiàn)office2003風(fēng)格。
組件的實(shí)現(xiàn)方法及原理
組件由三個(gè)類實(shí)現(xiàn),這三個(gè)類分別為OfficeMenus,MainMenuItemDrawing和MenuItemDrawing,都位于命名空間Dev4Arabs中。由于實(shí)現(xiàn)代碼較長,所以在此只給出了組件實(shí)現(xiàn)的思路。
組件實(shí)現(xiàn)的第一步是從System.ComponentModel.Component類派生類OfficeMenus。定義如下:
public class OfficeMenus : System.ComponentModel.Component
然后在類中定義兩靜態(tài)變量:
//圖像列表用來存儲(chǔ)菜單中用到的圖標(biāo)
static ImageList _imageList;
// 存儲(chǔ)圖片細(xì)節(jié)的一個(gè)名稱集合
static NameValueCollection picDetails = new NameValueCollection();
NameValueCollection的詳細(xì)說明請(qǐng)查閱MSDN,該類主要用來使每個(gè)菜單的句柄與每個(gè)圖標(biāo)形成一一對(duì)應(yīng)的關(guān)系,以便后面繪制菜單頂?shù)膱D標(biāo)時(shí)快速地找到某個(gè)菜單所對(duì)應(yīng)的圖標(biāo)。
接下來定義公共接口方法start和End。
Start方法有一個(gè)Form類類型的參數(shù),該方法從傳入的參數(shù)中獲得該窗口的主菜單。接下來為每一個(gè)主菜單下的MenuItem添加MeasureItem事件處理mainMenuItem_MeasureItem和DrawItem事件處理mainMenuItem_DrawItem,將MenuItem的OwnerDraw屬性設(shè)置為true,并使用InitMenuItem(Menu mi)方法對(duì)每個(gè)MenuItem應(yīng)用改變。然后再從form參數(shù)中獲取該窗口的上下文菜單對(duì)象,對(duì)其調(diào)用InitMenuItem(Menu mi)應(yīng)用改變。最后循環(huán)查找窗口中包含的每個(gè)子控件的上下文菜單,對(duì)其應(yīng)用改變。
公共接口方法Start的實(shí)現(xiàn)原理如下:
public void Start(Form form)
{
//從傳入的父窗體中獲得主菜單
System.Windows.Forms.MainMenu menu = form.Menu;
//循環(huán)每一個(gè)菜單項(xiàng),為其添加事件處理
foreach ( MenuItem mi in menu.MenuItems )
{
//訂閱MesaureItem事件處理
mi.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(mainMenuItem_MeasureItem);
//訂閱DrawItem事件處理
mi.DrawItem += new System.Windows.Forms.DrawItemEventHandler(mainMenuItem_DrawItem);
//將OwnerDraw屬性設(shè)置為true
mi.OwnerDraw = true;
//使用InitMenuItem(Menu mi)方法對(duì)每個(gè)MenuItem應(yīng)用改變
InitMenuItem(mi);
}
ContextMenu cmenu = form.ContextMenu;
if ( cmenu != null ) {InitMenuItem(cmenu);}
foreach ( Control c in form.Controls ) {
if ( c.ContextMenu != null )
InitMenuItem(c.ContextMenu);}
catch {}
}
End方法與這類似,只須將InitMenuItem換為UninitMenuItem.
為每個(gè)菜單應(yīng)用改變的InitMenuItem方法的實(shí)現(xiàn)如下:
循環(huán)查找mi中的每個(gè)MenuItem,為其添加MeasureItem事件處理menuItem_MeasureItem和DrawItem事件處理menuItem_DrawItem(注意,此處的事件處理方法名稱與Start中對(duì)主菜單的事件處理方法名稱不同),并將OwnerDraw屬性設(shè)置為true。使用遞歸調(diào)用對(duì)每個(gè)查找到的MenuItem調(diào)用InitMenuItem方法,這樣便可以對(duì)菜單項(xiàng)下的所有級(jí)別的子菜單項(xiàng)都應(yīng)用到改變。
private void InitMenuItem(Menu mi)
{
foreach ( MenuItem m in mi.MenuItems )
{
// 訂閱MesaureItem事件處理
m.MeasureItem +=
new System.Windows.Forms.MeasureItemEventHandler(this.menuItem_MeasureItem);
// 訂閱DrawItem事件處理
m.DrawItem +=
new System.Windows.Forms.DrawItemEventHandler(this.menuItem_DrawItem);
// 將OwnerDraw設(shè)置為true
m.OwnerDraw = true;
// 通過遞歸調(diào)用該方法對(duì)所有的子菜單進(jìn)行相同的設(shè)置
InitMenuItem(m);
}
}
新聞熱點(diǎn)
疑難解答