如何在MS-Project文件中存储自定义非任务数据(VSTO插件场景)
嘿,我正好做过类似的VSTO项目加载项开发,给你梳理下实现这个需求的关键步骤和代码示例,应该能帮到你!
核心思路
因为你只需要存储项目每周整体的实际工作量,不需要单个活动的统计数据,最贴合MSP数据结构的方案是:创建一个顶级虚拟汇总任务,然后给这个任务添加时间分段的实际工作量数据。这样既符合MSP的原生逻辑,后续生成挣值图时也能直接调用这些数据,不用额外做统计转换。
实现步骤
- 第一步:搭建VSTO开发环境
在Visual Studio里新建「Office/SharePoint」分类下的「Project 2016加载项」项目,选择C#语言,确保引用对应版本的MSP Interop程序集。 - 第二步:设计数据存储方案
创建一个名为「项目整体工作量汇总」的顶级汇总任务,专门用来承载每周的整体实际工作量(如果已经存在就复用,不存在则新建)。 - 第三步:对接外部系统数据
编写逻辑从你的统计系统拉取按周划分的实际工作量数据,建议封装成包含「周起始日期」和「实际工时」的实体类。 - 第四步:写入MSP文件
通过MSP的对象模型,把每周的工作量数据写入到汇总任务的时间分段字段中。 - 第五步:生成挣值图
可以直接用MSP自带的「挣值」报告(已经能识别汇总任务的时间分段数据),或者通过VSTO程序化生成自定义样式的图表。
代码示例
1. 引用必要命名空间
using Microsoft.Office.Core; using Microsoft.Office.Interop.MSProject; using System; using System.Collections.Generic; using System.Windows.Forms;
2. 定义工作量数据实体
// 对应外部系统返回的每周工作量数据结构 public class WeeklyWorkload { public DateTime WeekStartDate { get; set; } public double ActualWorkHours { get; set; } }
3. 获取/创建虚拟汇总任务
private Task GetOrCreateSummaryTask(Project project) { // 先检查是否已存在目标汇总任务 foreach (Task task in project.Tasks) { if (task.Name.Equals("项目整体工作量汇总", StringComparison.OrdinalIgnoreCase) && task.OutlineLevel == 1) { return task; } } // 不存在则创建新的顶级汇总任务 Task summaryTask = project.Tasks.Add("项目整体工作量汇总"); summaryTask.Summary = true; // 标记为汇总任务,避免被误操作 return summaryTask; }
4. 写入每周实际工作量到MSP
private void WriteWeeklyActualWork(Project activeProject, List<WeeklyWorkload> weeklyData) { Task summaryTask = GetOrCreateSummaryTask(activeProject); foreach (var workload in weeklyData) { // 计算周结束日期(假设周一为周起始,周日结束) DateTime weekEndDate = workload.WeekStartDate.AddDays(6); // 操作时间分段的实际工作量字段 TimeScaleValues timeScaleValues = summaryTask.TimeScaleData( StartDate: workload.WeekStartDate, EndDate: weekEndDate, Type: PjAssignmentTimescaledData.pjAssignmentTimescaledActualWork, TimeScaleUnit: PjTimescaleUnit.pjTimescaleWeeks, Count: 1); if (timeScaleValues.Count > 0) { timeScaleValues[1].Value = workload.ActualWorkHours; } } // 保存修改后的项目文件 activeProject.Save(); MessageBox.Show("每周实际工作量已成功写入MSP文件!"); }
5. 在加载项启动时调用(示例)
private void ThisAddIn_Startup(object sender, EventArgs e) { // 模拟从外部系统获取的样本数据 List<WeeklyWorkload> sampleWorkloads = new List<WeeklyWorkload> { new WeeklyWorkload { WeekStartDate = new DateTime(2024, 5, 6), ActualWorkHours = 135 }, new WeeklyWorkload { WeekStartDate = new DateTime(2024, 5, 13), ActualWorkHours = 150 }, new WeeklyWorkload { WeekStartDate = new DateTime(2024, 5, 20), ActualWorkHours = 142 } }; // 获取当前打开的MSP项目 Project currentProject = Application.ActiveProject; if (currentProject != null) { WriteWeeklyActualWork(currentProject, sampleWorkloads); } }
注意事项
- 单位转换:MSP的工作量默认单位是小时,如果你的外部系统用的是天/分钟等单位,记得提前转换。
- 权限问题:部署加载项时,要确保用户有修改.mpp文件的权限,尤其是在受保护的系统文件夹下。
- 计划工作量写入:如果需要把外部系统的计划工作量也导入,可以用同样的逻辑,把数据写入到汇总任务的「基准工时(Baseline Work)」字段中,这样MSP就能自动计算挣值指标。
- 版本兼容:确保引用的MSP Interop程序集版本和用户的MSP 2016匹配,避免兼容性问题。
内容的提问来源于stack exchange,提问作者Grumpy Curmudgeon
相关产品推荐
相关产品推荐

