天天看点

实现自定义LookupComboBox

微软套装的ComboBox本身就提供了AutoCompete功能,只要设置AutoCompleteMode和AutoCompleteSource属性即可,而且功能还是很强大的。但是…还是满足不了我的要求。

1. AutoComplete时下拉框只显示近似匹配的项,不是显示全部项并自动定位到匹配项。

2. 当输入的内容找不到匹配项时,还允许用户录入,并且SelectedIndex将为-1, 同时SelectedValue为null。

但是在多数情况下,我们是不允许用户输入选项以外的内容,输入只是进行lookup。而且SelectedIndex变为-1也不是所期盼的。因此,扩展ComboBox做了一个自定义控件。

1. 当获取焦点时全部文本默认是选中的,这时用户录入的内容就会代替全部内容去lookup。

2. 如果找到匹配项,就定位到匹配项,并且将文本的选中区域从用户录入内容向后选中;没有匹配项则录入无效。

3. 当用户退格或Del时,如果没有找到匹配项则只是将文本的选中区域扩大。

4. 当用户删除了内容时,如果没有找到匹配项则删除无效。如果用户要把内容全部删掉,就会跟据LimitedToList 属性来决定是否清空文本,当然也就是是否将SelectedIndex设置为-1。

5. 不允许Ctrl+X,最主要的原因是我在OnKeyPress事件中停止事件继续冒泡,这样剪切的内容并没有复制到剪切板。

6. 不允许ESC,原因是当下拉列表打开时ESC会将SelectedIndex恢复,但是用户录入匹配的文本不会恢复。

可能你注意到OnValidating方法。与OnLeave方法不同OnValidating方法不仅在失去焦点时会被调用,在用户使用快捷键触发按钮事件时也会被调用。后者对我来说更重要,因为用户都通过按钮的快捷键来完成保存操作,而快捷键并不会使ComboBox命运焦点,即不会调用OnLeave方法。

做这个控件还发生了一个波折,最初我是在OnTextChanged方法中完成匹配选中的,并且没有添加OnValidating方法,在我的本机(Windows 7)测试通过(当然除了用户按快捷键的情况)。但是用户使用的环境是XP和Windows 2003,Lookup匹配完成后ComboBox的SelectedIndex竞然是-1。

当然如果加上了OnValidatin方法也可以解决,但是使用overrid OnTextChanged的解决方案会引发多次TextChanged事件,最终还是改用了OnKeyPress方法。

顺便说一下,如果要在LookupComboBox的SelectedIndexChanged事件中想弹出一个确认对话框,让用户选是否或取消的那种,在弹框前要调用ComboBox.DroppedDown = false,这样ComboBox会接受lookup的最终结果。

如果你有更好的解决方案,请指教。