C# WPF使用FileSystemWatcher监听新建XML刷新DataGrid报ArgumentNullException
问题根因排查
- 你看到的
找不到UIElementAutomationPeer.cs提示是Visual Studio调试时缺少框架符号文件导致的,不属于业务代码问题,实际有效异常就是System.ArgumentNullException,由空对象访问触发。 - 保存文件的文件名拼接错误:你提供的
saveTableToXML方法中,文件路径硬编码为path + "\\.xml",没有拼接选中的ListView项名称,导致新建的文件实际名称为.xml(无主文件名),和你读取时拼接的selectedList.SelectedItem.ToString() + ".xml"完全不匹配。运行时新建文件后读取的是不存在的文件,虽然你捕获了打开文件的异常,但后续defaultData.Tables[0]访问时因为数据集为空,会抛出空参数异常。重启应用后你大概率是手动补了正确命名的文件,所以功能恢复正常。
- 保存文件的文件名拼接错误:你提供的
- FileSystemWatcher的Changed事件会被多次触发:文件写入过程中会多次触发Changed事件,此时文件可能还未被写入操作完全释放,就算加了
FileShare.ReadWrite也可能读取到不完整的XML内容,导致defaultData.ReadXml加载失败,数据集为空,后续访问Tables[0]抛出异常。
- FileSystemWatcher的Changed事件会被多次触发:文件写入过程中会多次触发Changed事件,此时文件可能还未被写入操作完全释放,就算加了
- 缺少加载结果校验:读取XML后没有判断
defaultData.Tables.Count是否大于0,直接访问Tables[0],一旦读取失败就会抛出空参数异常。
- 缺少加载结果校验:读取XML后没有判断
- 文件流未使用using自动释放:多处FileStream操作没有用using语法,可能存在资源残留占用,导致后续读写文件失败。
- 全局定义的FileSystemWatcher不需要刷新配置,只要监听路径正确,运行时新建的xml文件会自动被监听,不需要额外调整。
修复方案
步骤1:修正保存方法的文件名拼接
private void saveTableToXML() { // 先判断是否有选中项,避免空引用 if (userListView.SelectedItem == null) return; DataTable dt = ((DataView)dataGridName.ItemsSource).ToTable(); // 用Path.Combine拼接路径,避免不同系统的分隔符兼容问题 string filePath = Path.Combine(path, $"{userListView.SelectedItem.ToString()}.xml"); try { // 使用using自动释放文件流,避免资源残留占用 using FileStream file = File.Create(filePath); dt.WriteXml(file, XmlWriteMode.WriteSchema, false); } catch(Exception ex) { MessageBox.Show(ex.Message); } }
步骤2:优化刷新方法,增加空校验
private void refreshDataGrid(DataGrid dataGridName, ListView selectedList, string path) { if (selectedList.SelectedItem == null) return; string filePath = Path.Combine(path, $"{selectedList.SelectedItem.ToString()}.xml"); if (!File.Exists(filePath)) return; try { using FileStream file = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); defaultData.Tables.Clear(); defaultData.ReadXml(file); // 新增表存在校验,避免访问空对象 if (defaultData.Tables.Count > 0) { dataGridName.ItemsSource = defaultData.Tables[0].DefaultView; } } catch (Exception x) { MessageBox.Show(x.Message); } }
步骤3:优化FileSystemWatcher触发逻辑,避免重复调用和无效刷新
// 新增防抖锁,避免同一文件多次变更重复触发刷新 private bool _isRefreshing = false; private void FileWatcher_Changed(object sender, FileSystemEventArgs e) { if (_isRefreshing) return; // 只刷新当前选中项对应的文件,避免无关文件变更触发无效刷新 if (userListView.SelectedItem == null || e.FullPath != Path.Combine(path, $"{userListView.SelectedItem.ToString()}.xml")) { return; } _isRefreshing = true; Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)(() => { try { // 延迟100ms等待文件写入完成,避免读取到半写入的损坏内容 Task.Delay(100).Wait(); refreshDataGrid(dataGridName, userListView, path); } catch(Exception) { // 忽略非核心异常 } finally { _isRefreshing = false; } })); }
内容的提问来源于stack exchange,提问作者Hasarr
相关产品推荐
相关产品推荐

