SaveFileDialog AddExtension 无法按预期工作

Posted

技术标签:

【中文标题】SaveFileDialog AddExtension 无法按预期工作【英文标题】:SaveFileDialog AddExtension doesn't work as expected 【发布时间】:2019-04-16 14:51:55 【问题描述】:

我有以下 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 nameSave 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 框架对其进行了测试。在这种情况下,永远不会创建双重扩展,例如:test3.abc 使用 MONO 与 test3.abc.txt 使用 .NET Framework 4.5 (Windows 10)。

【问题讨论】:

来自FileDialog.AddExtension Property:“获取或设置一个值,该值指示对话框是否自动为文件名添加扩展名如果用户省略扩展名。 我使用FilterIndex 属性来决定是否应该将其存储为txtxml 文件,而不是FileName 属性的扩展名。 @LarsTech 但是,如果用户在文件名中添加了不在所选文件过滤器中的扩展名 (Save type as),那么我希望有一个双扩展名,例如 *.abc.txt。它为abc 等所有未知(系统)扩展添加了双重扩展,并且没有为bmp 等所有已知(系统)扩展添加双重扩展。但我不能指望用户知道系统知道哪些扩展。 该链接提到 CheckFileExists = true。在你的帖子中没有看到,所以试试吧。 @LarsTech CheckFileExists=true 属性对 SaveFileDialog 没有意义。如果文件不存在,我不想看到警告。 【参考方案1】:

Source code on my Github (batressc)

简单来说,除*.abc 之外的所有扩展名都是Windows 操作系统中有效的文件类型扩展名。当您在true 中设置AddExtension 属性时,仅当您放置未注册的文件扩展名时,.NET Framework 才会自动在保存文件对话框中自动补全具有所选文件扩展名值的文件名。

在这个例子中:

    在我的Windows 10操作系统中,我没有注册文件类型扩展名*.abc(我们可以使用regedit.exe查看HKEY_CLASSES_ROOT下的文件类型扩展名)

    我用预期的结果测试“test3.abc”案例

    我在HKEY_CLASSES_ROOT 中注册了*.abc 文件类型扩展名,只创建了一个名为.abc 的新密钥

    我重复第 2 点,现在 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;
        
    

我们可以使用FileNameForceExtension,而不是使用FileName。就我而言,我使用它的形式:

textBoxFileName.Text = dialog.FileName + " | " + dialog.FileNameForceExtension();

这是使用test7.xml*.txt 文件扩展名的结果:

注意事项

在 Windows 窗体 (FileDialog.cs on GitHub) 的 FileDialog 的实现中,未指定使用 OS 函数或方法查找文件扩展名的代码中,GetExtensionHasExtension 方法仅在 .&lt;extension&gt; 处验证模式文件名的最后一个 (Path.cs on GitHub)。也许在 Windows 操作系统中注册扩展的验证是框架的内部功能,这对开发人员来说是不可见的...... :(

【讨论】:

此解决方案不满足以下要求:我不想在对话框关闭后执行此操作,因为我必须再次检查文件是否已存在以及文件名是否为不会太长。【参考方案2】:

所以我知道现在回答有点晚了,因为您可能已经继续前进,但是对于将来来这里寻找答案的其他人,就像我自己刚刚所做的那样,答案是:唯一的方法是让您自己的 SaveFiledialog 控件或修改现有的 Using A partial Class that Inherits SaveFiledialog。 Microsoft 将其标记为不可继承。许多基类以某种方式受到保护,以阻止人们修改它们。这是一种荒谬的不必要的痛苦,但事实就是如此。即使您设法获得了该类的副本,它也依赖于一堆其他受保护的东西。您最好的选择是完全自己制作或尝试解析文件名并添加扩展名,如果它不像其他人所说的那样自己存在。是的,这很糟糕,因为一旦添加了扩展名,文件名可能会变得太长,但您无能为力。但是,Windows 10 上文件名的最大长度为 260 个字符,包括扩展名。用户很少会尝试将文件命名那么长。这不是你应该留给机会的事情,但微软让我们别无选择。一种选择是,如果用户不使用消息框,则只要求用户添加扩展名,然后再次显示对话框。如果至少有一个属性可以将对话框的最大文件名长度设置为自定义长度(这在比我可能添加的更多场景中有用。@microsoft)那么这将允许您考虑可能需要添加扩展程序,但甚至没有选项可以这样做。

【讨论】:

以上是关于SaveFileDialog AddExtension 无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

c# savefiledialog 保存特定长度的文本

带有 Savefiledialog 的 *** 异常

禁用部分 SaveFileDialog

使用SaveFileDialog保存文件

不使用 SaveFileDialog 保存文件

saveFileDialog:文件名无效