List Control的ItemChange消息

在使用MFCCListCtrl时,用得最多的就是LVN_ITEMCHANGEDLVN_ITEMCHANGING两个消息了,它们通常都是成对出现。可是,我们经常认为只有Select一个Item时才会产生这两个消息。其实,这两个消息的意思是某个item发生了变化,包括:状态变化和数据变化。其中,状态变化通常是由SetItemState引起的,数据变化是由SetItemData引起的。消息的数据封装在NMLISTVIEW结构中。对于SetItemData,该结构中的state成员均为0。另外,DeleteItem会引发LVN_ITEMCHANGING消息(但不会引发LVN_ITEMCHANGED消息),此时,state成员也为0(无效)。

       既然会有这么多情况产生这两个消息,那么我们在这两个消息的响应函数中做一些事情时,应该加以区分,否则会执行多次,很可能引起错误的结果。例如:我们希望在选择另一个item前,提示用户是否需要保存当前选择的item。此时,只需要判断NMLISTVIEW结构中的uNewState是否是选中状态(LVIS_SELECTED)。可以对于非状态时的上下文,仅仅从该结构中是无法判断的,比如:DeleteItemSetItemData等,此时,需要自己管理上下文来加以判断。通常,这两种方法所产生的item变化消息,我们并不关心。

       另外,我们注意到,当状态由有状态变为无状态(0),消息的发送是原子的;而由无状态变为有状态,则只有一次。比如:某个Item处于选中且有焦点(LVIS_FOCOUSED | LVIS_SELECTED),此时,如果选中另一Item,此时的消息序列如下:

(3)item changing(old state:2-new state:0)

(3)item changed(old state:2-new state:0)

(3)item changing(old state:1-new state:0)

(3)item changed(old state:1-new state:0)

(2)item changing(old state:0-new state:3)

(2)item changed(old state:0-new state:3)

格式为:(item序号)消息类型(old state:旧状态-new state:新状态)

其中,LVIS_SELECTED2LVIS_FOCOUSED1 

此外,即使是已经处于选中状态的Item,当再次被选中时,仍然会引起如下的消息序列(真不知道MS是出于什么目的?):

(3)item changing(old state:3-new state:3)

(3)item changing(old state:2-new state:0)

(3)item changed(old state:2-new state:0)

(3)item changing(old state:1-new state:3)

(3)item changed(old state:1-new state:3)

而并不是如我们想象的不产生上述两个消息。如果只关心选中状态,那么这些消息序列就需要过滤掉,否则会产生多少重复的行为!

    另外,还有两个容易产生问题的场景:

1.  LVN_ITEMCHANGING响应方法中,使用CListCtrl提供的方法无法获得当前选中的条目序号(而在其它场景下,是没有问题的。注意此时获得的选中条目,并不是NMLISTVIEW结构中的iItem,而是前一个被选中的条目,假设是单选风格)。

原因:CListCtrl在发送该通知消息前,如果不是多选模式(CtrlShift),会将所有ItemsSelect状态清除。(缺省的行为是左键选择某个条目,前面所有选择的条目的状态都会被清除)

解决办法:在所在类中,增加一个成员,用来记录上次选中的条目。记录的时机就可以放在这两个消息的响应方法中。

2.  如果在这两种消息的响应方法中,弹出一个模态对话框,最常见的就是MessageBox,比如:在用户选择另一个Item前,提示用户某种信息。此时,如果在多选风格下,当对话框关闭后,会呈现出和下面动作一样的画面,即:使用鼠标左键拖动选中一批Item,且未释放左键。

原因:模态对话框的出现使得本来应该list control响应的WM_LBUTTONUP消息没有再发生。对话框显示后,list control将收到WM_CANCELMODE消息,在系统的DefWindowProc方法中,该消息会将取消如下内容:标准滚动条输入的内部处理、内部的菜单处理、captured鼠标。

解决办法:在LVN_ITEMCHANGED响应方法中,Post一个WM_LBUTTONUP消息,使得一个选择条目的动作序列得以完整结束。注意,既然我们希望该消息发生在当前消息结束之后, 所以应该是Post,而不是Send.否则,当然没有效果

 

你可能感兴趣的:(list,mfc)