我有以下C#代码,它使用SaveFileDialog,并将AddExtension属性设置为true
:
var dialog = new SaveFileDialog();
dialog.AddExtension = true;
dialog.DefaultExt = "txt";
dialog.Filter = "Text files (*.txt)|*.txt|XML files (*.xml)|*.xml";
dialog.OverwritePrompt = true;
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
label1.Text = dialog.FileName;
}
我已经测试了对话框的File name
和Save as type
的以下组合。
File name | Save as type | label1.Text | What I expect
----------------+----------------+----------------+----------------
test1 | *.txt | test1.txt | test1.txt
test2.txt | *.txt | test2.txt | test2.txt
test3.abc | *.txt | test3.abc.txt | test3.abc.txt
test4 | *.xml | test4.xml | test4.xml
test5.xml | *.xml | test5.xml | test5.xml
test6.abc | *.xml | test6.abc.xml | test6.abc.xml
----------------+----------------+----------------+----------------
test7.xml | *.txt | test7.xml | test7.xml.txt
test8.bmp | *.txt | test8.bmp | test8.bmp.txt
test9.bmp | *.xml | test9.bmp | test9.bmp.xml
对于上表的最后三行,我希望像未知的abc
扩展名一样使用双扩展名。像Microsoft Word这样的应用程序的行为是这样的(如果Save as type
与用户在File name
中给定的扩展名不匹配,它们总是添加双扩展名。)
有办法改变吗?
在对话框关闭后我不想这样做,因为那我必须再次检查文件是否已经存在以及文件名是否太长。
更新:
我已经使用Ubuntu 18.04在MONO框架上进行了测试。在这种情况下,永远不会创建双扩展名,例如:使用MONO的test3.abc
与使用.NET Framework 4.5(Windows 10)的test3.abc.txt
。
答案 0 :(得分:1)
Source code on my Github (batressc)
简单来说,除*.abc
外的所有扩展名在Windows OS中都是有效的文件类型扩展名。在AddExtension
中设置true
属性时,仅当您放置未注册的文件扩展名时,.NET Framework才会在保存文件对话框中自动自动完成具有所选文件扩展名的文件名。
在此示例中:
*.abc
(我们可以使用HKEY_CLASSES_ROOT
在regedit.exe
下查看文件类型扩展名)*.abc
中注册了HKEY_CLASSES_ROOT
文件类型扩展名,只是创建了一个名称为.abc
的新密钥txt
部分不可见要解决此问题,我们可以创建一个扩展方法,他可以确保在保存文件对话框中添加选定的扩展名。
// It's good practice create extensions methods in the same namespace of the class to extend
namespace System.Windows.Forms {
public static class SaveFileDialogFileTypeExtension {
// Retrieving only text of the file extensions
private static List<string> GetFileExtensions(string filter) {
List<string> extensions = new List<string>();
var filtersRaw = filter.Split('|');
for (int i = 0; i < filtersRaw.Length; i++) {
if (i % 2 != 0) {
// Supporting multi doted extensions
extensions.Add(filtersRaw[i].Trim().Replace("*", "").Substring(1));
}
}
return extensions;
}
// Getting filename with selected extension
public static string FileNameForceExtension(this SaveFileDialog dialog) {
string fileName = dialog.FileName;
// Retrieving the current selected filter index
List<string> extensions = GetFileExtensions(dialog.Filter);
string selectedExtension = extensions[dialog.FilterIndex - 1];
// Adding extension if need it
if (!fileName.EndsWith($".{selectedExtension}")) {
fileName = $"{fileName}.{selectedExtension}";
}
return fileName;
}
}
}
我们可以使用FileName
来代替FileNameForceExtension
。就我而言,我使用以下形式:
textBoxFileName.Text = dialog.FileName + " | " + dialog.FileNameForceExtension();
这是使用test7.xml
和*.txt
文件扩展名的结果:
注释
在Windows窗体(FileDialog.cs on GitHub)的FileDialog
的实现中,未指定使用OS函数或方法,GetExtension
和HasExtension
方法查找文件扩展名的代码仅在文件名(Path.cs on GitHub)的最后验证模式.<extension>
。也许Windows OS中注册扩展的验证是Framework的一项内部功能,对于开发人员来说这是不可见的...:(
答案 1 :(得分:0)
所以我知道现在回答有点晚了,因为您可能已经继续前进了,但是对于将来像我自己一样来这里寻找答案的其他人来说,这里的答案是:做到这一点的唯一方法是 make您自己的 SaveFiledialog 控件或使用继承 SaveFiledialog 的部分类修改现有控件。微软将其标记为不可继承。许多基类都以某种方式受到保护,以阻止人们修改它们。这是一种荒谬的不必要的痛苦,但事实就是如此。即使您设法获得了该类的副本,它也依赖于一堆其他受保护的东西。您最好的选择是完全自己制作或尝试解析文件名,然后添加扩展名,如果它不像其他人所说的那样自己存在。是的,这很糟糕,因为一旦你添加了扩展名,文件名可能会变得太长,但你无能为力。但是,Windows 10 上文件名的最大长度为 260 个字符,包括扩展名。用户很少会尝试命名这么长的文件。这不是你应该听天由命的事情,但微软让我们别无选择。一种选择是,如果用户不使用消息框,则只要求用户添加扩展名,然后再次显示对话框。如果至少有一个属性可以将对话框的最大文件名长度设置为自定义长度(这在更多场景中很有用,而不仅仅是我可能会添加。@microsoft)那么这将允许您考虑可能需要添加扩展程序,但甚至没有选项可以这样做。