在 Vista/Windows 7 WPF FileDialog.Filter 中隐藏扩展

Posted

技术标签:

【中文标题】在 Vista/Windows 7 WPF FileDialog.Filter 中隐藏扩展【英文标题】:Hide extensions in Vista/Windows 7 WPF FileDialog.Filter 【发布时间】:2011-08-09 15:03:54 【问题描述】:

我在我的 .NET 4 WPF 应用程序中使用 WPF OpenFileDialog 和 SaveFileDialog。我使用 Filter 属性来允许用户设置不同的文件过滤器。在 .NET 4 中,这使用 Windows Vista 引入的本机文件对话框(如果可能)。

但是,这些对话框显示构成文件过滤器的扩展名。由于其中一些使用了相当多的扩展,这很丑陋。

例如,我有一个过滤器Image files|*.bmp;*.dib;*.jpg;*.jpeg;*.jpe;*.jfif;*.gif;*.tif;*.tiff;*.png;*.ico|All files|*.*,在对话框中显示为Image files (*.bmp;*.dib;*.jpg;*.jpeg;*.jpe;*.jfif;*.gif;*.tif;*.tiff;*.png;*.ico)。括号中的所有内容都是自动添加的,即根据过滤器字符串,它应该显示Image files。但是在某处添加了括号中的内容。我尝试用 Reflector 查看代码,看看它是否在某个地方完成,但很快就放弃了,因为它非常复杂。

例如,开始绘制,我可以看到可以使用这些文件对话框而不用括号中的内容,即它显示Image files

有人知道这个“功能”的解决方法吗?

【问题讨论】:

我从未见过自动添加过滤器元素的行为。您正在使用的 OpenFileDialog 的完整命名空间是什么? 大声笑刚刚在 Windows 7 上的 VS 2010 中尝试过这个,现在我得到了同样的结果...... 我正在使用 Microsoft.Win32.OpenFileFilter。没有自动添加过滤器元素。而是自动添加括号中的内容。 我使用了以下代码,它只显示“图像文件”部分:'OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "图像文件|*.bmp;*.dib;*.jpg;*.jpeg;*.jpe;*.jfif;*.gif;*.tif;*.tiff;*.png;*. ico|所有文件|*.*"; ofd.ShowDialog();'. WPF 4,赢 7。 要查看扩展名,您必须在 Windows 资源管理器设置中禁用“隐藏已知文件类型的扩展名”。 【参考方案1】:

你在正确的轨道上。有两种有效的方式来显示打开的文件对话框。较新的方法使用IFileOpenDialog(扩展IFileDialog)。使用此方法,过滤器描述和文件规范使用COMDLG_FILTERSPEC 结构定义。这让分开的人进入了自己的领域,这更自然。

如果您想使用此方法从组合框中删除文件规范,那么您必须添加自己的自定义控件或操作对话框上的组合框控件。虽然这会变得混乱,但应该是可行的。

老派方法使用GetOpenFileName 和OPENFILENAME 结构。这个技巧是可以显示一个旧外观或新外观的对话框。外观由 OPENFILENAME 结构中的设置决定,如 here 所述。

WinForms OpenFileDialog 的问题在于,当 AutoUpgradeEnabled 为 true 时,它​​们要么使用 IFileOpenDialog,而当 AutoUpgradeEnabled 为 false 时,它​​们使用旧外观的 GetOpenFileName。

WPF 版本没有给您选择,但仍使用与 WinForms 相同的逻辑,但会根据需要自动执行。对于 .NET 4 中的 WPF 也是如此,在以前的版本中,它只会使用带有旧外观的 GetOpenFileName。

Paint 最有可能使用具有新外观的 GetOpenFileName。这是一个 C# 示例:

private delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

private const int OFN_ALLOWMULTISELECT = 0x00000200;
private const int OFN_CREATEPROMPT = 0x00002000;
private const int OFN_DONTADDTORECENT = 0x02000000;
private const int OFN_ENABLEHOOK = 0x00000020;
private const int OFN_ENABLEINCLUDENOTIFY = 0x00400000;
private const int OFN_ENABLESIZING = 0x00800000;
private const int OFN_ENABLETEMPLATE = 0x00000040;
private const int OFN_ENABLETEMPLATEHANDLE = 0x00000080;
private const int OFN_EXPLORER = 0x00080000;
private const int OFN_EXTENSIONDIFFERENT = 0x00000400;
private const int OFN_FILEMUSTEXIST = 0x00001000;
private const int OFN_FORCESHOWHIDDEN = 0x10000000;
private const int OFN_HIDEREADONLY = 0x00000004;
private const int OFN_LONGNAMES = 0x00200000;
private const int OFN_NOCHANGEDIR = 0x00000008;
private const int OFN_NODEREFERENCELINKS = 0x00100000;
private const int OFN_NOLONGNAMES = 0x00040000;
private const int OFN_NONETWORKBUTTON = 0x00020000;
private const int OFN_NOREADONLYRETURN = 0x00008000;
private const int OFN_NOTESTFILECREATE = 0x00010000;
private const int OFN_NOVALIDATE = 0x00000100;
private const int OFN_OVERWRITEPROMPT = 0x00000002;
private const int OFN_PATHMUSTEXIST = 0x00000800;
private const int OFN_READONLY = 0x00000001;
private const int OFN_SHAREAWARE = 0x00004000;
private const int OFN_SHOWHELP = 0x00000010;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class OPENFILENAME_I 
    public int lStructSize;
    public IntPtr hwndOwner;
    public IntPtr hInstance;
    public string lpstrFilter;
    public IntPtr lpstrCustomFilter;
    public int nMaxCustFilter;
    public int nFilterIndex;
    public IntPtr lpstrFile;
    public int nMaxFile = 260;
    public IntPtr lpstrFileTitle;
    public int nMaxFileTitle = 260;
    public string lpstrInitialDir;
    public string lpstrTitle;
    public int Flags;
    public short nFileOffset;
    public short nFileExtension;
    public string lpstrDefExt;
    public IntPtr lCustData;
    public WndProc lpfnHook;
    public string lpTemplateName;
    public IntPtr pvReserved;
    public int dwReserved;
    public int FlagsEx;


[DllImport("comdlg32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool GetOpenFileName([In, Out] OPENFILENAME_I ofn);

private void ShowOpenFileDialog() 
    OPENFILENAME_I ofn = new OPENFILENAME_I();
    ofn.lStructSize = Marshal.SizeOf(typeof(OPENFILENAME_I));
    ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files\0*.*\0\0";
    ofn.nFilterIndex = 0;
    //ofn.Flags = OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING | OFN_NODEREFERENCELINKS | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
    ofn.Flags = OFN_ENABLESIZING | OFN_NODEREFERENCELINKS | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
    GetOpenFileName(ofn);

您可以尝试重新添加OFN_EXPLORER 和/或OFN_ENABLEHOOK 标志,它会恢复到旧外观。但照原样,上面的代码将显示一个打开的文件对话框,其中所有文件都没有显示它的文件规范。

【讨论】:

非常感谢。我想我会跳过这一步,因为它会导致大量工作以进行大多数用户不会注意到的微小改进...【参考方案2】:

经过一堆测试,我得到以下结果: WPF 中的 FileDialog 使用过滤器定义的字符串调用本机 IFileDialog::SetFileTypes 方法。根据 Windows 选项隐藏已知文件类型的扩展名(在 Windows 资源管理器文件夹设置中),是否自动添加扩展名。

现在唯一的问题是,Paint 如何在其打开的文件对话框中不显示“图像文件”的扩展名。

【讨论】:

【参考方案3】:

你可能想去这里……

Hide Extensions

【讨论】:

【参考方案4】:

我不喜欢 GetOpenFileName 和 WinForm 的 AutoUpgradeEnabled=false 对话框的 GUI。

为了修复 WPF 的对话框,我编写了一个实现 IDisposable 的小类,在构造函数中我检查 HideFileExt 值是否设置为 0HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced 注册表项下,如果它是 0 我在此处写入1,在只读字段中保持密钥打开,并在释放类时恢复0

使用示例:

bool result;
using( var hfe = new HideExplorerExtensions() )
    result = ofd.ShowDialog( ownerWindow ) ?? false;

更简洁的方法是补丁 RegGetValueW 或任何其他 API comdlg32.dll!CFileOpenSave::Show(struct HWND__ *) 方法用于读取该值,例如MinHook 因此只有当前进程中托管的对话框才能在该注册表值中看到1。然而,这要复杂得多。

【讨论】:

以上是关于在 Vista/Windows 7 WPF FileDialog.Filter 中隐藏扩展的主要内容,如果未能解决你的问题,请参考以下文章

Java (+- JNA) 中有没有办法在 XP+Vista+Windows 7 中可靠地设置主系统音量?

在 Windows Vista、Windows 7 中截屏,应用区域外有透明区域

WPF中的Windows 8风格魅力栏? [关闭]

Windows 7 蓝屏代码大全 & 蓝屏全攻略

Windows 7 GUI 参考

如何获取 Vista/Windows7 等列表视图