我在.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查看代码,看看它是否在某个地方完成,但很快就放弃了,因为它很复杂。
启动Paint,例如,我可以看到可以使用这些文件对话框,而不包括括号中的内容,即它显示Image files
。
有没有人知道这个“功能”的解决方法?
答案 0 :(得分:5)
你走在正确的轨道上。实际上有两种显示打开文件对话框的方法。较新的方法使用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
标记,然后它将恢复为原貌。但按原样,上面的代码将显示一个打开的文件对话框,其中所有文件都没有显示它的文件规范。
答案 1 :(得分:1)
经过一系列测试后,我得到了以下结果:WPF中的FileDialog使用过滤器定义的字符串调用本机IFileDialog::SetFileTypes方法。根据Windows选项隐藏已知文件类型的扩展名(在Windows资源管理器文件夹设置中),扩展名会自动添加或不自动添加。
现在唯一的问题是Paint如何在其打开的文件对话框中无法显示“图像文件”的扩展名。
答案 2 :(得分:1)
你可能想到这里......
答案 3 :(得分:0)
我不喜欢GetOpenFileName或WinForm对话框(带有AutoUpgradeEnabled = false)的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
。但是,这要复杂得多。