Visual Studio 2010响应Ribbon控件消息

开发 后端
利用XML文件定义和描述Ribbon界面,从分工的意义上讲,其实那是UI设计师的活儿。作为程序员,更加专注的是如何令Visual Studio 2010响应Ribbon控件,完成相应的业务逻辑。

Visual Studio 2010与Windows 7的完美配合,在本文中体现在Visual Studio 2010响应Ribbon控件消息上。UI美工们已经帮我们完成了设计工作,下面现在,该轮到程序员上场了!51CTO编辑推荐《Visual Studio 2010应用与开发详解

在Ribbon界面编辑完成的基础上,我们来看看如何利用Windows Scenic Ribbon API处理各种控件消息,让Ribbon界面真正地投入使用。

如何利用XML文件创建Ribbon控件,对控件进行排布和设置控件的缩放策略等等,可以说,这些工作都是UI设计师的任务。对程序员来说,更重要的是对控件的消息进行处理实现其业务逻辑。

添加消息处理功能

我们可以创建了一个派生自IUIApplication的Ribbon界面宿主对象类CApplication,并利用这个类完成了Ribbon界面的创建,初始化以及与Windows应用程序的集成。要对Ribbon控件的消息进行处理,我们还是要借助这个宿主对象类。为了使得CApplication类具有控件消息处理的能力,我们需要修改它的定义,让它同时也从IUICommandHandler派生。而IUICommandHandler类,则是Scenic Ribbon API提供给我们的控件消息处理类,只要CApplication从这个类派生,就具有了相应的控件消息的处理能力。

为了对Visual Studio 2010响应Ribbon控件消息进行处理,我们修改CApplication类的定义如下:

  1. // 引入Scenic Ribbon API的头文件  
  2. #include <uiribbon.h> 
  3. // 引入编译生成的资源头文件  
  4. #include "ribbonres.h"  
  5. // 调用Windows API获得系统时间  
  6. #include "windows.h"  
  7. #include "stdio.h"  
  8.  
  9. IUIFramework* g_pFramework = NULL;  
  10. // Ribbon界面宿主程序  
  11. class CApplication  
  12.     : public CComObjectRootEx<CComMultiThreadModel> 
  13.         , public IUIApplication  // 处理Ribbon界面的创建和初始化  
  14.         , public IUICommandHandler // 处理Ribbon控件的消息 

然后,我们需要利用COM_INTERFACE_ENTRY宏定义COM_MAP,在CApplication类的定义中,添加:

  1. public:  
  2.     BEGIN_COM_MAP(CApplication)  
  3.           COM_INTERFACE_ENTRY(IUIApplication)  
  4.                   COM_INTERFACE_ENTRY(IUICommandHandler)  
  5.     END_COM_MAP() 

这样,Visual Studio 2010响应Ribbon控件的消息就会发送到CApplication类,由CApplication类进行处理。在整个Scenic Ribbon API中,Ribbon控件消息的处理流程如下图所示。除了之前我们介绍的跟Ribbon界面创建和初始化相关的过程之外,为了完成控件消息,我们首先需要为感兴趣的控件进行注册,这些工作都会在OnCreateCommand函数中完成。完成控件的注册后,当我们需要进行消息处理的控件有消息发生时,IUIFramework就会将这些消息发送给CApplication,而我们就可以在CApplication类中对具体的消息进行处理。Ribbon控件的消息主要分成两种:一种是来自控件的动作消息,比如按钮控件被点击,ComboBox的选择发生了变化等。这类消息都在Execute函数中进行处理;另外一种是则对控件属性进行更新的消息,这类消息在UpdateProperty函数中进行处理。

UpdateProperty函数

注册感兴趣的控件

按照Ribbon界面控件消息的处理流程,我们首先需要在OnCreateCommand函数中为我们感兴趣的控件进行注册,这样当控件有动作发生的时候,CApplication类才会收到相应的控件消息,进而可以对其进行处理。在CApplication类的OnCreateCommand函数中,我们完成相应控件的注册:

  1. STDMETHOD(OnCreateUICommand)(UINT32 nCmdID, __in UI_COMMANDTYPE typeID, __deref_out IUICommandHandler** ppCommandHandler)   
  2.     {   
  3.         // 对相应控件的消息进行注册  
  4.         if (nCmdID == cmdMyButton   
  5.             || nCmdID == cmdDeleteTable  
  6.             || nCmdID == cmdAddTable  
  7.             || nCmdID == cmdPrintRelationships)  
  8.         {  
  9.             return QueryInterface(IID_PPV_ARGS(ppCommandHandler));  
  10.         }  
  11.         return E_NOTIMPL;   
  12.     } 

在这段代码中,我们根据控件的Symbol选取了几个需要进行消息处理的控件,当这几个控件有动作发生时,比如比鼠标点击,或者是进行了选择,IUIFramework会发送相应的消息给宿主对象CApplication,从而让我们可以有机会对这些消息进行处理。

处理控件消息

对于普通的控件点击消息或者是选择消息等动作消息,我们需要重写CApplication类的消息处理函数Execute函数,在其中对消息进行处理:

  1. // 消息处理函数  
  2. STDMETHODIMP Execute(UINT nCmdID,  
  3.         UI_EXECUTIONVERB verb,   
  4.         __in_opt const PROPERTYKEY* key,  
  5.         __in_opt const PROPVARIANT* ppropvarValue,  
  6.         __in_opt IUISimplePropertySet* pCommandExecutionProperties)  
  7.     {  
  8.         HRESULT hr = S_OK;  
  9.  
  10.         switch (verb)  
  11.         {  
  12.                         // 只处理感兴趣的消息类型  
  13.         case UI_EXECUTIONVERB_EXECUTE:  
  14.                                     // 判断消息来源  
  15.             if (nCmdID == cmdMyButton)  
  16.             {  
  17.                                                // 执行具体的业务逻辑  
  18.                                                // 这里我们获得系统时间并进行输出  
  19.                 SYSTEMTIME sys;  
  20.                 GetLocalTime( &sys );  
  21.                 wchar_t strInfo[256] = L"";  
  22.                 wsprintf( strInfo, L"当前系统时间:  
  23. %4d/%02d/%02d %02d:%02d:%02d.%03d 星期%1d\n",  
  24.                     sys.wYear,sys.wMonth,sys.wDay,  
  25.                     sys.wHour,sys.wMinute,sys.wSecond,sys.wMilliseconds,  
  26.                     sys.wDayOfWeek);  
  27.                  // 显示消息框  
  28.                                                  MessageBox(NULL, strInfo,  
  29.                     L"当前系统时间”,  
  30.                     MB_OK);  
  31.             }  
  32.             break;  
  33.         }      
  34.         return hr;  
  35.     } 

现在编译运行这个解决方案,当我们点击cmdMyButton 所对应的“MyButton”这个按钮时,就可以得到一个消息框报告当前的系统时间。当然,我们这里只是对按钮控件的动作进行处理,对于其他类型控件的消息处理,都是按照相同的流程进行。

按钮控件的点击事件
图2  按钮控件的点击事件

在运行时对控件属性进行修改

在某些情况下,我们需要在运行时对控件的属性进行修改。例如,在应用程序运行的某种状态下,我们可能需要禁用某些控件,或者是修改控件的标签文本,图标等等。对控件属性的修改,可以通过直接修改控件属性达到,也可以通过调用InvalidateUICommand函数刷新控件的属性,然后在UpdateProperty函数中进行控件属性更改消息处理,实现具体的属性修改。下面我们分别来看看这两种方式是如何进行的。

在这个例子中,我们处理两个按钮控件的点击消息,让他们分别禁用另外的按钮控件和修改按钮的标签文本。在Execute函数中,处理相应的按钮消息,实现控件属性的改变:

  1. STDMETHODIMP Execute(UINT nCmdID,  
  2.         UI_EXECUTIONVERB verb,   
  3.         __in_opt const PROPERTYKEY* key,  
  4.         __in_opt const PROPVARIANT* ppropvarValue,  
  5.         __in_opt IUISimplePropertySet* pCommandExecutionProperties)  
  6.     {  
  7.         HRESULT hr = S_OK;  
  8.  
  9.         switch (verb)  
  10.         {  
  11.         case UI_EXECUTIONVERB_EXECUTE:  
  12.             if (nCmdID == cmdMyButton)  
  13.             {  
  14.                 //  
  15.                 PROPVARIANT varNew;  
  16.  
  17.                 BOOL _fEnabled = FALSE;  
  18.                                                 // 初始化属性值  
  19.                 hr = UIInitPropertyFromBoolean(UI_PKEY_Enabled,  
  20.                                                          _fEnabled, &varNew);  
  21.                 if (FAILED(hr))  
  22.                 {  
  23.                     return hr;  
  24.                 }  
  25.                                                 // 为控件cmdDeleteTable设置新的属性值  
  26.                 hr = g_pFramework->SetUICommandProperty(cmdDeleteTable,   
  27.                                                         UI_PKEY_Enabled, varNew);  
  28.                 if (FAILED(hr))  
  29.                 {  
  30.                     return hr;  
  31.                 }  
  32.             }  
  33.             else if (nCmdID == cmdAddTable)  
  34.             {  
  35.                 // 发送属性更新消息对控件属性UI_PKEY_Label进行更新  
  36.                 hr = g_pFramework->InvalidateUICommand(  
  37.                                                              cmdPrintRelationships,  
  38.                                                              UI_INVALIDATIONS_PROPERTY, &UI_PKEY_Label);  
  39.                 if (FAILED(hr))  
  40.                 {  
  41.                               return hr;  
  42.                 }  
  43.             }  
  44.             break;  
  45.         }      
  46.         return hr;  
  47.     } 

在cmdMyButton按钮的消息处理中,我们使用SetUICommandProperty就可以直接修改控件的属性了。在这里,我们通过设置cmdDeleteTable按钮控件的UI_PKEY_Enabled属性为FALSE,达到了禁用这个控件的目的。而在cmdAddTable按钮的消息处理中,我们只是调用了IUIFramework的InvalidateUICommand函数,这表示它会自动调用CApplication类的UpdateProperty来实现控件属性的更新,所以对于第二种方式,我们还需要实现这个函数,在其中完成属性的更新:

  1. STDMETHODIMP UpdateProperty(UINT nCmdID,  
  2.         __in REFPROPERTYKEY key,  
  3.         __in_opt const PROPVARIANT* ppropvarCurrentValue,  
  4.         __out PROPVARIANT* ppropvarNewValue)  
  5.     {  
  6.         UNREFERENCED_PARAMETER(ppropvarCurrentValue);  
  7.  
  8.         HRESULT hr = E_FAIL;  
  9.  
  10.         if (key == UI_PKEY_Label)  
  11.         {  
  12.             // 更新控件cmdPrintRelationships的标签文本  
  13.             if (nCmdID == cmdPrintRelationships)  
  14.             {  
  15.                 hr = UIInitPropertyFromString(UI_PKEY_Label,   
  16.                         L"New Label", ppropvarNewValue);  
  17.             }  
  18.         }  
  19.         return hr;  
  20.     } 

现在,我们就可以编译运行整个解决方案,点击相应的按钮控件,就可以看到对控件属性修改的效果了:

修改控件属性
图3  修改控件属性

到这里,我们完成了整个Ribbon历程:从创建XML文件到添加宿主对象,从创建到初始化,从控件消息处理到控件属性更新。现在,Ribbon界面对我们来说,已经不再仅仅是微软的一种界面技术,她切切实实地来到了我们身边,可以为我们所用,提高应用程序的用户体验。

拥抱Ribbon,拥抱Windows 7,拥抱Visual Studio 2010!

【编辑推荐】

  1. 微软称C++将得到Visual Studio 2010更多支持
  2. Visual Studio 2010新特性:动态语言功能
  3. 微软对Visual Studio 2010的Bug熟视无睹?
  4. Visual Studio 2010 Beta1试用手记
  5. Visual Studio 2010重要新功能一览
责任编辑:彭凡 来源: ITPUB
相关推荐

2010-04-16 14:08:46

Visual Stud

2009-11-12 12:42:35

Visual Stud

2009-12-02 09:43:38

Visual Stud

2010-02-23 09:02:00

Visual Stud

2009-11-13 09:05:05

Visual Stud

2009-11-10 13:43:37

Visual Stud

2010-02-22 16:43:33

Visual Stud

2009-11-11 09:48:06

Visual Stud

2009-11-13 10:12:37

Visual Stud

2009-12-11 13:14:45

Visual Stud

2011-02-13 17:10:28

Visual Stud

2009-11-13 14:59:12

Visual Stud

2010-04-06 17:32:02

Visual Stud

2010-04-12 08:43:45

Visual Stud

2009-11-11 14:26:13

Visual Stud

2009-11-10 15:27:42

Visual Stud

2010-03-22 16:38:31

Visual Stud

2009-11-10 15:12:21

Visual Stud

2010-02-24 15:04:54

Visual Stud

2009-04-23 14:05:28

Visual Stud历史调试功能
点赞
收藏

51CTO技术栈公众号