问题
I've the following C# code, which is using the SaveFileDialog and set's the AddExtension property to 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;
}
And I've tested the following combination of File name
and Save as type
of the dialog.
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
For the last three lines of the above table I would expect a double extension like it does for the unknown abc
extension. Applications like Microsoft Word behave like that (they always add the double extension if the Save as type
doesn't match the extension given by the user in File name
).
Is there a way to change that?
I don't want to do it after the dialog is closed because then I've to check again if the file already exists and if the file name is not too long.
Update:
I've tested it as well with the MONO framework using Ubuntu 18.04. In that case a double extension is never created, e.g.: test3.abc
using MONO vs test3.abc.txt
using .NET Framework 4.5 (Windows 10).
回答1:
Source code on my Github (batressc)
In simple terms, all extensions except *.abc
are valid file type extension in Windows OS. When you set AddExtension
property in true
, only if you put a unregistered file extension, .NET Framework autocomplete automatically the file name with value of selected file extension in the save file dialog.
In this example:
- In my Windows 10 OS, I don't have registered the file type extension
*.abc
(We can view file type extensions underHKEY_CLASSES_ROOT
usingregedit.exe
)
- I test "test3.abc" case with the expected result
- I register the
*.abc
file type extension inHKEY_CLASSES_ROOT
only creating a new key with name.abc
- I repeat point 2 and now the
txt
part is not visible
To fix this, we can create an extension method that he makes sure to add the selected extension in the save file dialog
// 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;
}
}
}
Instead to use FileName
we can use FileNameForceExtension
. In my case, I use it that form:
textBoxFileName.Text = dialog.FileName + " | " + dialog.FileNameForceExtension();
And this is the result using test7.xml
with *.txt
file extension:
NOTES
In the implementation of FileDialog
of Windows Forms (FileDialog.cs on GitHub) inside the code not specified to find the file extensions using OS functions or methods, GetExtension
and HasExtension
methods only validate the pattern .<extension>
at last of the file name (Path.cs on GitHub). Maybe the validation of the registered extensions in the Windows OS is an internal functionality of the Framework and this is not visible for the developer... :(
来源:https://stackoverflow.com/questions/55711039/savefiledialog-addextension-doesnt-work-as-expected