那阵子给七亿批量远程管理工具(RdpManager)的文件窗口补列头排序。补完当天,列头点上去,纹丝不动。

本地、远程四个文件列表都得能按列头排——名称、大小、修改时间,点一下升序,再点换降序,文件夹和“..”永远钉在最前面。SFTP 那两个列表本来就有这功能,FTP 这两个是这回补的。先在 SFTP 上试,一点就排,好的;切回 FTP,点“名称”没反应,点“大小”还是没反应。

第一反应是比较器写错了。把那几个比较函数拎出来单独跑,升序降序都对。那就不是算的问题,是事件压根没进来。

挂上断点,ColumnClick 一次都没触发。回去翻 ListView 属性才想起来:HeaderStyle 我没设,默认值不是 Clickable。列头长得像能点,其实点了不发 ColumnClick。我脑子里一直把“列头可点”当成 ListView 的默认行为,这是我第一个想岔的地方。

改成 ColumnHeaderStyle.Clickable,心想这下总该好了。结果还是点不到。

第二个坑更阴。文件窗口的布局是上面一条路径栏、下面一个文件列表,我用 Dock 拼的:路径栏 Dock=Top,列表 Dock=Fill。坏就坏在我把路径栏加在了列表前面。WinForms 的停靠是按反向 z 序处理的,先加进去的反而被后加的压住——那条路径栏正好盖在列表顶部的列头上。看着列头在那儿,鼠标其实点在路径栏上。把添加顺序倒过来,先加列表(Fill)、再加路径栏(Top),列头露出来,也点得动了。记一笔:Dock 布局里谁盖谁,跟代码里谁先 Add 是反的。

以为收工了。真用起来又冒出一下:每个列表的列头只能点一次,第一下会排,再点想切降序就不动了,跟死了一样。

这回没猜,直接去翻 ListView 排序那套 API。原因是它有毛病——反复设同一个 Sorting 值不会触发重新排序。我原来的写法是每次点击都去改 Sorting(Ascending / Descending 来回切),碰上“值没变”的情形,它就不重排了。改法是每次点击都换一个全新的 sorter,再显式调一次 lv.Sort();降序就把比较器用 ReverseComparer 包一层,Sorting 固定成 Ascending(非 None 的 ListView 才会去用 sorter)。这样每点必排,升降也切得动。改动落在 FtpForm / SftpForm 的 EnableColumnSort 里。到这儿,七亿批量远程管理工具这四个列表算是暂时老实了。

回头看,这两个坑一个栽在“属性默认值”,一个栽在“库的行为怪癖”,都不沾算法。写界面最磨人的,往往就是这种你不亲手点一下都发现不了的“默认”和“惯例”——代码挑不出错,点下去才知道它不动。

SFTP 那边为什么一开始没事?它那两个列表早设过 Clickable、布局顺序也是对的。等于我先试的那半台,恰好把所有坑都藏起来了。

想看带这版修复的包,官网的七亿批量远程管理工具下载页一直在。文件窗口里这种“点不动”的界面毛病,之前防火墙窗口那个跑到窗口外头的控件算一个,经典列表点分组折叠弹系统错误框也算一个——都是对着同一个列表控件来回掰。

(顺带一提,七亿批量远程管理工具 v1.6.1是免费的 Windows 端工具,RDP 九宫格 / SSH 终端 / SFTP / FTP 那一套都有,要试从官网下就行。)