新增钻带刀序多种排序功能及相关文档
本次提交主要内容如下: - 新增“排序功能”菜单,支持重排刀序、生成/应用排序种子、按参考钻带重排等多种排序方式,提升刀具顺序管理灵活性。 - 支持用户选择参考钻带文件或排序种子文件,自动重排当前刀具顺序,并提供详细的匹配校验、警告提示和重排前后对比确认。 - 新增生成通用排序种子文件(General_sort.txt)功能,便于批量产品排序。 - 优化界面布局,提升信息展示美观性和空间利用率。 - 增加异常处理和详细注释,提升健壮性和可维护性。 - 新增多个文档,详细说明“使用指定钻带的刀序”功能的实现、使用方法、演示流程及开发过程中的问题修复,便于开发和用户理解。 - 新增两个排序种子文件示例(General_sort.txt、s40024079g0-a2-cs-jp-sort.txt),用于刀具顺序自动重排。 - 其他无实际代码变更的文件未影响功能。 本次改动极大提升了钻带刀具顺序管理的自动化、灵活性和用户体验,适用于多样化的生产场景。
This commit is contained in:
126
Docs/跨线程问题修复说明.md
Normal file
126
Docs/跨线程问题修复说明.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 跨线程问题修复说明
|
||||
|
||||
## 问题描述
|
||||
|
||||
在实现"使用指定钻带的刀序"功能时,遇到了以下错误:
|
||||
|
||||
```
|
||||
使用参考钻带重排失败:该类型的CollectionView不支持从调度程序线程以外的线程对其SourceCollection进行的更改。
|
||||
```
|
||||
|
||||
## 问题分析
|
||||
|
||||
这是一个典型的WPF跨线程操作问题:
|
||||
|
||||
### 根本原因
|
||||
- `ObservableCollection<ToolItem> Tools` 是UI绑定的集合
|
||||
- 在WPF中,UI元素(包括ObservableCollection)只能在UI线程中修改
|
||||
- 我们的代码在`Task.Run()`中直接调用了`SortToolsByDiameterList(Tools, referenceDiameters)`
|
||||
- 该方法会修改Tools集合,但此时处于后台线程
|
||||
|
||||
### 错误位置
|
||||
```csharp
|
||||
// 在 ReorderToolsByReferenceDrillTape() 方法中
|
||||
System.Threading.Tasks.Task.Run(() =>
|
||||
{
|
||||
// ... 其他代码 ...
|
||||
|
||||
// 这里在后台线程中直接修改UI集合
|
||||
SortToolsByDiameterList(Tools, referenceDiameters); // ❌ 错误!
|
||||
|
||||
// ... 其他代码 ...
|
||||
});
|
||||
```
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 修复方法
|
||||
将所有对UI集合的修改操作都包装在`Dispatcher.Invoke()`中,确保在UI线程执行:
|
||||
|
||||
```csharp
|
||||
// 修复后的代码
|
||||
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. 正确的跨线程操作模式
|
||||
```csharp
|
||||
// ❌ 错误:在后台线程中直接修改UI集合
|
||||
Task.Run(() =>
|
||||
{
|
||||
observableCollection.Add(item); // 会抛出异常
|
||||
});
|
||||
|
||||
// ✅ 正确:在后台线程中处理数据,在UI线程中更新UI
|
||||
Task.Run(() =>
|
||||
{
|
||||
var data = ProcessHeavyWork(); // 后台处理
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
observableCollection.Add(data); // UI线程更新
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Dispatcher使用技巧
|
||||
```csharp
|
||||
// 方法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集合修改都在正确的线程中执行,从而解决了跨线程操作异常。
|
||||
|
||||
这个修复不仅解决了当前的问题,还为未来的功能开发提供了线程安全的编程模式参考。
|
||||
Reference in New Issue
Block a user