如何通过VSTO插件将员工工时导入Microsoft Project的TimeScaleData
工时导入Microsoft Project的报错修复方案
核心报错原因
Assignments.Add抛出System.Runtime.InteropServices.COMException的直接原因是新创建的任务未设置有效时间范围——Microsoft Project要求任务必须有明确的开始/结束日期才能创建资源分配,否则会判定参数无效。此外代码中还存在变量初始化不规范的潜在问题。
分步修复
1. 为任务设置有效时间范围
创建任务后,立即将Phase的BaselineStart和BaselineFinish赋值给任务的Start和Finish属性,确保任务有合法的时间区间:
Task newPhaseTask = project.Tasks.Add(phase.Name); // 绑定任务时间范围,解决分配创建的核心限制 newPhaseTask.Start = DateTime.Parse(phase.BaselineStart); newPhaseTask.Finish = DateTime.Parse(phase.BaselineFinish);
2. 修复assignmentExists变量初始化问题
遍历员工的每个工时日期前,必须重置assignmentExists为false,否则第一次检测到分配存在后,后续循环会持续跳过创建逻辑:
foreach (var date in emp.EntryDates) { bool assignmentExists = false; // 每次循环重新初始化 foreach (Assignment assignment in newPhaseTask.Assignments) { if (assignment.Resource.Name.Equals(resource.Name, StringComparison.OrdinalIgnoreCase)) { assignmentExists = true; break; } } // 后续创建分配或更新工时的逻辑 }
3. 优化资源查找逻辑(可选)
用LINQ简化资源查找代码,提升可读性:
Resource resource = project.Resources.Cast<Resource>() .FirstOrDefault(r => r.Name.Equals(emp.Name, StringComparison.OrdinalIgnoreCase)); if (resource == null) { resource = project.Resources.Add(emp.Name); }
4. 修正TimeScaleData的工时赋值逻辑
Project的工时单位默认是分钟,且TimescaleValues集合的Add方法并非直接传入日期和小时,正确方式是修改对应日期的Value值:
TimescaleValues tsValues = targetAssignment.TimeScaleData( date.DateEntered, date.DateEntered, PjAssignmentTimescaledData.pjAssignmentTimescaledWork, PjTimescaleUnit.pjTimescaleDays, 1); if (tsValues.Count > 0) { // 将小时转换为分钟,匹配Project的工时单位 tsValues[1].Value = date.Hours * 60; }
完整修复代码
Project project = Globals.ThisAddIn.Application.ActiveProject; Task newPhaseTask = project.Tasks.Add(phase.Name); // 设置任务有效时间范围 newPhaseTask.Start = DateTime.Parse(phase.BaselineStart); newPhaseTask.Finish = DateTime.Parse(phase.BaselineFinish); foreach (Employee emp in Employees) { // 查找或创建对应资源 Resource resource = project.Resources.Cast<Resource>() .FirstOrDefault(r => r.Name.Equals(emp.Name, StringComparison.OrdinalIgnoreCase)); if (resource == null) { resource = project.Resources.Add(emp.Name); } // 检查是否已存在该资源的任务分配 bool assignmentExists = false; Assignment targetAssignment = null; foreach (Assignment assignment in newPhaseTask.Assignments) { if (assignment.Resource.Name.Equals(resource.Name, StringComparison.OrdinalIgnoreCase)) { assignmentExists = true; targetAssignment = assignment; break; } } // 不存在则创建新分配 if (!assignmentExists) { targetAssignment = newPhaseTask.Assignments.Add(resource); } // 为每个日期写入工时数据 foreach (var date in emp.EntryDates) { TimescaleValues tsValues = targetAssignment.TimeScaleData( date.DateEntered, date.DateEntered, PjAssignmentTimescaledData.pjAssignmentTimescaledWork, PjTimescaleUnit.pjTimescaleDays, 1); if (tsValues.Count > 0) { tsValues[1].Value = date.Hours * 60; } } }
内容的提问来源于stack exchange,提问作者sridharnetha
相关产品推荐
相关产品推荐

