My Silverlight系列(8)—— 关于Silverlight 2 RC0中的ComboBox

上个月的25号,微软发布了Silverlight 2 RC0,用于Silverlight2的正式RTW版发布之前,为程序员提供的一个过渡版本。让人高兴的是在这个版本中,微软的Silverlight小组履诺为我们做出了三个通用控件,分别是ProgressBar、ComboBox和PasswordBox。相对而言,这三个控件的使用是比较简单的,甚至不会比Button难到哪里去,今天在这里我也无需说明这几个控件怎么使用,我只是想谈谈ComboBox实现中微软用的一个小技巧。

关于ComboBox,有一个特性是需要注意的,即在Dropdown的状态下,如果用户点击了ComboxBox的DropDown之外任何一个地方,那个DropDown就应该自动收起来。由于最终实现DropDown的container是一个Popup,因此只需要改变这个Popup的IsOpen属性即可。但是问题的关键就是什么时候去改变它,应该在哪一个事件触发时去改变它。上面说过,是用户点击了DropDown之外的一个地方,这是非常棘手的一个事情,因为势必我们不是点击了DropDown内的某处,那么就无法在DropDown内部订阅某个事件。我曾经想过通过LostFocus事件去做这个事情,但是经过尝试,发现并不可行,那个事件在点击到别的地方时并不触发。在Silverlight的官网上,我和几个人讨论过这个问题,有人提出了用MouseLeave加一个Timer去做,和某些JavaScript的Dropdown一样,只要鼠标移出了Dropdown的区域,在较短的时间内就将其关闭。但是这并不是一多很好的Solution,而且在WinForm下,一般也没有人会这么处理。前两天在我升级了RC0之后,我惊喜地发现微软的ComboBox是有这个功能的,我就去研究了一番。最终发现他在做这个Dropdown的时候,为Dropdown做了一个能够占满整个application区域的透明的Canvas,并且为它加上了MouseLeftButtonDown事件。由于Silverlight的MouseLeftButtonDown事件是无法Click-Through的,因此其他控件都不会有任何反应,只是被这个透明的Canvas截获并做出了相应的处理。其实这个workaround也是有他的弊端的,如果仔细研究winform的dropdown,可以发现如果点击了别处的一个button,除了dropdown隐藏起来之外,button的事件一样也触发了,但是微软这么做的这个ComboBox,只有等它收起来之后再点一回,那个Button才会有反应。不过相较而言,微软这么做已经算是一个比较好的解决方案,至少不会出现当我们把ComboBox移动之后,DropDown不跟着走这样的BUG。

另外,这个想法应该也不是微软的原创,从前在讨论Modal-Dialog的实现的时候,就有人提出来做一个透明的Canvas来避免在ShowDialog之后,底下的控件仍然会响应鼠标的点击事件。但是这个方法也不完美,鼠标不work了不代表键盘不行,总之有办法让你不爽的。

因此我想建议MSFT的就是,尽可能找出一种更好的解决方案,主要是在消息机制方面,让Silverlight更像WPF/E,而不只是一个模仿。虽然其中困难重重,但是我认为也是指日可待的。

你可能感兴趣的:(silverlight)