Files
AohDrllTools/Docs/跨线程问题修复说明.md
Mr.Xia 837cf6fb12 新增钻带刀序多种排序功能及相关文档
本次提交主要内容如下:

- 新增“排序功能”菜单,支持重排刀序、生成/应用排序种子、按参考钻带重排等多种排序方式,提升刀具顺序管理灵活性。
- 支持用户选择参考钻带文件或排序种子文件,自动重排当前刀具顺序,并提供详细的匹配校验、警告提示和重排前后对比确认。
- 新增生成通用排序种子文件(General_sort.txt)功能,便于批量产品排序。
- 优化界面布局,提升信息展示美观性和空间利用率。
- 增加异常处理和详细注释,提升健壮性和可维护性。
- 新增多个文档,详细说明“使用指定钻带的刀序”功能的实现、使用方法、演示流程及开发过程中的问题修复,便于开发和用户理解。
- 新增两个排序种子文件示例(General_sort.txt、s40024079g0-a2-cs-jp-sort.txt),用于刀具顺序自动重排。
- 其他无实际代码变更的文件未影响功能。

本次改动极大提升了钻带刀具顺序管理的自动化、灵活性和用户体验,适用于多样化的生产场景。
2025-12-28 13:16:41 +08:00

3.5 KiB
Raw Permalink Blame History

跨线程问题修复说明

问题描述

在实现"使用指定钻带的刀序"功能时,遇到了以下错误:

使用参考钻带重排失败该类型的CollectionView不支持从调度程序线程以外的线程对其SourceCollection进行的更改。

问题分析

这是一个典型的WPF跨线程操作问题

根本原因

  • ObservableCollection<ToolItem> Tools 是UI绑定的集合
  • 在WPF中UI元素包括ObservableCollection只能在UI线程中修改
  • 我们的代码在Task.Run()中直接调用了SortToolsByDiameterList(Tools, referenceDiameters)
  • 该方法会修改Tools集合但此时处于后台线程

错误位置

// 在 ReorderToolsByReferenceDrillTape() 方法中
System.Threading.Tasks.Task.Run(() =>
{
    // ... 其他代码 ...
    
    // 这里在后台线程中直接修改UI集合
    SortToolsByDiameterList(Tools, referenceDiameters); // ❌ 错误!
    
    // ... 其他代码 ...
});

解决方案

修复方法

将所有对UI集合的修改操作都包装在Dispatcher.Invoke()确保在UI线程执行

// 修复后的代码
System.Threading.Tasks.Task.Run(() =>
{
    // ... 其他代码 ...
    
    // ✅ 正确在UI线程中修改集合
    System.Windows.Application.Current.Dispatcher.Invoke(() =>
    {
        progressText.Text = "正在重排刀具顺序...";
        SortToolsByDiameterList(Tools, referenceDiameters);
    });
    
    // ... 其他代码 ...
});

修复的关键点

  1. UI集合修改:所有对Tools集合的修改都必须在UI线程中执行
  2. 进度更新进度文本的更新也需要在UI线程中执行
  3. 异步处理:保持异步处理的优势,避免界面冻结

WPF线程安全最佳实践

1. UI元素访问规则

  • UI控件只能在UI线程中访问
  • ObservableCollection只能在UI线程中修改
  • 依赖属性只能在UI线程中修改

2. 正确的跨线程操作模式

// ❌ 错误在后台线程中直接修改UI集合
Task.Run(() =>
{
    observableCollection.Add(item); // 会抛出异常
});

// ✅ 正确在后台线程中处理数据在UI线程中更新UI
Task.Run(() =>
{
    var data = ProcessHeavyWork(); // 后台处理
    
    Application.Current.Dispatcher.Invoke(() =>
    {
        observableCollection.Add(data); // UI线程更新
    });
});

3. Dispatcher使用技巧

// 方法1使用Invoke同步等待
Application.Current.Dispatcher.Invoke(() =>
{
    // UI操作代码
});

// 方法2使用BeginInvoke异步执行
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
    // UI操作代码
}), DispatcherPriority.Background);

修复验证

编译测试

  • 代码编译成功,无语法错误
  • 修复了跨线程操作问题

功能测试

  • 异步处理保持界面响应
  • UI集合修改在正确的线程中执行
  • 进度提示正常更新

总结

这个问题的核心是WPF的线程安全机制。在WPF中任何与UI相关的操作都必须在UI线程中执行包括

  1. UI控件的属性修改
  2. ObservableCollection的修改
  3. 依赖属性的更新
  4. UI绑定的数据源修改

通过将SortToolsByDiameterList()调用包装在Dispatcher.Invoke()我们确保了所有UI集合修改都在正确的线程中执行从而解决了跨线程操作异常。

这个修复不仅解决了当前的问题,还为未来的功能开发提供了线程安全的编程模式参考。