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

问题描述 投票:7回答:4

我在.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

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

wpf windows-7 .net-4.0
4个回答
5
投票

您走在正确的轨道上。实际上,有两种显示打开文件对话框的方法。较新的方法使用IFileOpenDialog(扩展了IFileDialog)。使用此方法,可以使用COMDLG_FILTERSPEC结构定义过滤器描述和文件规范。这将分隔符保留在各自的字段中,这更加自然。

如果要使用此方法从组合框中删除文件规格,则必须添加自己的自定义控件或在对话框上操作组合框控件。虽然这样会很混乱,但是应该可行。

[旧方法使用GetOpenFileNameOPENFILENAME结构。这样做的窍门是可以显示具有旧外观或新外观的对话框。外观由OPENFILENAME结构中的设置确定,如here所述。

WinForms OpenFileDialog的问题是,当说AutoUpgradeEnabled为true时,它们要么使用IFileOpenDialog,当AutoUpgradeEnabled为false时,它们使用具有较旧外观的GetOpenFileName。

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

最有可能使用具有新外观的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标志,它会恢复为旧外观。但按原样,上面的代码将显示一个打开文件对话框,其中“所有文件”不显示其文件规范。


1
投票

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

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


1
投票

您可能想去这里...

Hide Extensions


0
投票

我既不喜欢GetOpenFileName的GUI,也不喜欢带有AutoUpgradeEnabled = false的WinForm对话框的GUI。

[为了修复WPF的对话框,我编写了一个实现IDisposable的小类,在构造函数中,我检查HideFileExt注册表项下的0值是否设置为HKCU\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。但是,这要复杂得多。

© www.soinside.com 2019 - 2024. All rights reserved.