Windows

WPF使用System.Windows.OpenFileDialog选择文件夹

这几天在重温C#.Net-WPF,拿个以前废弃的项目练练手,其中遇到一个问题:

WPF自身的命名空间System.Windows中没有打开文件夹的对话框,只有OpenFileDialog可以打开文件。

网上搜了很多帖子,无外乎三种答案

  1. 使用以前WinForm的FolderBrowserDialog:为了避免命名空间冲突导致的代码繁琐(两边都有OpenFileDialog)以及出于一些洁癖的原因,我这次决定坚决不使用WinForm,反正自己做项目也没工期什么的,大不了不做了~
  2. 扩写System.Windows.OpenFileDialog:要么自己扩写,要么用一些别人写好的开源组件,一个是太麻烦,另一个心里总觉得不太舒服
  3. 使用微软官方的扩展包Microsoft.WindowsAPICodePack:这个看起来很不错,但是也有缺点,就是完全要求Windows版本>=6.0,而公司的电脑还是杯具的5.1,只能放弃

正在纠结之际,国外著名社区 Stack Overflow 上看到这么一篇帖子:

原帖地址

一位大佬想出了一个看起来很orz的方法,不过反正也没其他解决方案,姑且一试。

这位大佬将Filter设置成一个非常非常长的扩展名从而起到隐藏所有文件的目的:

openFileDialog1.Filter = "folders|*.neverseenthisfile"

然后把文件名设为一个”r”换行符来骗过OpenFileDialog,这样只要不改动文件名就能直接按打开按钮。当然同时还需要把CheckFileExists给false掉……

我修改了他的原型代码后得到了如下版本:

OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "folders|*.sado;fjsdal;fj";
ofd.FileName = "r";
ofd.CheckFileExists = false;
ofd.CheckPathExists = true;
ofd.ValidateNames = false;
if (ofd.ShowDialog() == true)
{
	ofd.FileName = ofd.FileName.TrimEnd('r');
	int lastSeparatorIndex = ofd.FileName.LastIndexOf('\');
	ofd.FileName = ofd.FileName.Remove(lastSeparatorIndex);
	txtCOutputPath.Text = ofd.FileName;
}

运行后成功取到了目录,并且哪怕不当心在文件文本框里输入了内容也可以正常工作了。本以为事情到此为止,我甚至都把这篇博文发表了出来(第一稿是到这行的前一个句号就结束的),到家后再试才发现家里的娜娜不买账!!!

仔细研究后,发现貌似娜娜不认ValidateNames属性,不论这个值是true还是false,她一定会检查文件名是否合法……好在她并不在意文件是否真的存在,所以代码稍加修改还是可以用:

OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = CoffeeScript._ofdOutputFilter;
ofd.FileName = "Filename will be ignored";
ofd.CheckFileExists = false;
ofd.CheckPathExists = true;
//ofd.ValidateNames = false;
if (ofd.ShowDialog() == true)
{
	//ofd.FileName = ofd.FileName.TrimEnd('r');
	int lastSeparatorIndex = ofd.FileName.LastIndexOf('\');
	ofd.FileName = ofd.FileName.Remove(lastSeparatorIndex);
	txtCOutputPath.Text = ofd.FileName;
	return true;
}
return false;

不过这种做法还是有一定问题的,如果用户不当心选中了一个文件夹,那他后面的麻烦就大了……看来这个问题还需要再研究一下……

在Windows下使用Nginx不使用额外工具隐藏命令行窗口

在网上搜了一下关于这个主题的帖子,基本无外乎两种:

  1. 使用工具把Nginx注册为Windows服务
  2. 使用工具隐藏命令行窗口

其实根本不需要额外的工具,自己写个很简单的Windows批处理文件就能解决问题:

start /B nginx

这个/B参数就是让程序隐藏在后台不生成新的CMD窗口。至于要结束的时候,只需要调用nginx自己的stop/quit信号就可以了。

下面稍微深入一点讲一下:以前有用过nginx,尤其是在Linux下用过的前辈,都知道nginx有两个不同的信号(stop和quit)用来结束,其中”stop”信号是等待任务完成正常结束,而”quit”是强退。所以,如果喜欢鼠标双击的方式操作,只需要给他们各写一份bat文件就行;而如果更多地是在命令行下操作,可以把他们写在一个bat里,不过直接使用nginx自己的-s参数也并没麻烦到哪里去吧。

不过,在Windows下有一点需要注意的是:nginx使用pid文件来保存进程信息,如果我们不小心运行了两份nginx,后一份的pid文件会把前一份的给覆盖掉,所以用-s quit和-s stop命令就只能结束最后一份nginx进程。所以,可以在quit.bat里加入”tskill nginx”这一行,在quit结束之后,再杀一次进程。至于stop命令里,因为是需要让它干净地退出,所以就不要加这个命令了。

::start.bat

start /B nginx

::stop.bat

nginx -s stop

::quit.bat

nginx -s quit
tskill nginx

::reload.bat

nginx -s reload

::reopen.bat

nginx -s reopen

另外再附上两份命令行用的bat:

::偷懒的方式

@ECHO OFF
IF "%1"=="" (
	GOTO :start
) ELSE IF "%1"=="start" (
	GOTO :start
) ELSE IF "%1"=="quit" (
	GOTO :quit
) ELSE (
	GOTO :s
)

:start
start /B nginx
GOTO :end

:quit
nginx -s quit
tskill nginx
GOTO :end

:s
nginx -s %1
GOTO :end

:end

::方便自己起别名的方式

@ECHO OFF
IF "%1"=="" (
	GOTO :start
)ELSE IF "%1"=="start" (
	GOTO :start
)ELSE IF "%1"=="stop" (
	GOTO :stop
)ELSE IF "%1"=="quit" (
	GOTO :quit
)ELSE IF "%1"=="reload" (
	GOTO :reload
)ELSE IF "%1"=="reopen" (
	GOTO :reopen
) ELSE (
	GOTO :end
)

:start
start /B nginx
GOTO :end

:stop
nginx -s stop
GOTO :end

:quit
nginx -s quit
tskill nginx
GOTO :end

:reload
nginx -s reload
GOTO :end

:reopen
nginx -s reopen
GOTO :end

:end