OpenFileDialog.ShowDialog() 返回值必须检查,正确做法是先判断 DialogResult.OK(WinForms)或 true(WPF)再访问 FileName 或 FileNames,否则可能因用户取消导致空路径引发异常;多选需用 FileNames 数组;WPF 应使用 Microsoft.Win32.OpenFileDialog。

OpenFileDialog.ShowDialog() 返回值必须检查,否则可能空引用
很多人直接调用 ShowDialog() 后就去读 FileName,但用户点“取消”或关闭对话框时,它返回的是 DialogResult.Cancel(或 null 在某些上下文中),此时 FileName 是空字符串,FileNames 是空数组——如果后续没判空就直接传给 File.ReadAllText() 之类的方法,会抛出 ArgumentException 或 FileNotFoundException。
正确做法是先判断返回值:
var dialog = new OpenFileDialog();
dialog.Filter = "文本文件|*.txt|所有文件|*.*";
if (dialog.ShowDialog() == DialogResult.OK) {
string path = dialog.FileName; // 此时才安全
string content = File.ReadAllText(path);
}
-
ShowDialog()是模态阻塞调用,必须等用户操作完才继续执行 - WinForms 应用中推荐用
DialogResult.OK判断;WPF 中需改用bool?判断(true表示确认) - 不要依赖
FileName.Length > 0做判断——某些系统或高 DPI 下可能返回带空格的路径,长度不为 0 但实际无效
多选文件时 FileNames 和 FileName 的行为差异
启用多选(MultiSelect = true)后,FileName 只返回第一个选中的路径,而 FileNames 返回完整字符串数组。新手常误以为 FileName 会拼接所有路径,结果只处理了第一个文件。
示例场景:批量导入日志文件
var dialog = new OpenFileDialog();
dialog.Multiselect = true;
dialog.Filter = "日志文件|*.log";
if (dialog.ShowDialog() == DialogResult.OK) {
foreach (string file in dialog.FileNames) { // 必须用 FileNames
ProcessLog(file);
}
}
-
FileName在Multiselect = true时仍可用,但仅作“预览第一个”用途 -
FileNames数组元素不含重复项,但不保证顺序与用户点击顺序完全一致(取决于 Shell 排序逻辑) - 路径含中文或特殊字符时,
FileNames已自动转义,无需额外Uri.UnescapeDataString
Filter 和 FilterIndex 配合使用容易忽略的细节
Filter 决定界面上显示哪些类型选项,FilterIndex 控制默认选中第几个。常见错误是只设 Filter 却忘了设 FilterIndex,导致默认选中“所有文件”,用户一不小心就选到非预期扩展名的文件。
比如想默认只显示 JSON 文件:
dialog.Filter = "JSON 文件|*.json|配置文件|*.config|所有文件|*.*"; dialog.FilterIndex = 1; // 注意:从 1 开始计数,不是 0
-
FilterIndex超出范围(如设为 0 或大于项数)会被静默重置为 1 - 修改
Filter后必须重新设FilterIndex,否则沿用旧值,可能指向不存在的项 - 若程序支持拖入文件,建议在
DragDrop事件里也做扩展名校验,不能只信界面 Filter
在 WPF 中不能直接用 WinForms 的 OpenFileDialog
WPF 默认没有引用 System.Windows.Forms,强行 new OpenFileDialog() 会编译失败。有人搜到“WPF OpenFileDialog”却照搬 WinForms 写法,卡在引用和初始化上。
两种解法:
- 添加 NuGet 包
System.Windows.Forms(.NET 5+ 需额外启用 Windows Forms 支持) - 更推荐用 WPF 原生的
Microsoft.Win32.OpenFileDialog(位于PresentationFramework程序集)
WPF 原生写法示例:
var dialog = new Microsoft.Win32.OpenFileDialog();
dialog.DefaultExt = ".txt";
dialog.Filter = "文本文件|*.txt";
bool? result = dialog.ShowDialog(); // 返回 bool?,不是 DialogResult
if (result == true) {
string path = dialog.FileName; // 同样要判 result 才安全
}
注意:Microsoft.Win32.OpenFileDialog 没有 Multiselect 属性,多选需用 Microsoft.Win32.OpenFileDialog 的替代方案(如第三方库或自定义窗口),这点常被忽略。










