前期说明:在Project2007中可以选择一个团队项目(TFS),然后在Project2007中排好进度,作为工作项发布到TFS服务器上。之后可以直接作为工作项在VS2005等工具中填写项目进度。本文的目的就是要显示出TFS中保存的实时项目进度情况等。
技术说明:在Project2007之前的版本可以通过oledb的方式直接读取project的mpp文件来显示进度,在project2007时不再提供oledb的方式了,可能的两种实现方法有:
1、使用Project2007提供的COM接口,读取mpp文件中的任务 + TFS中的实时进度
2、把所有的进度安排(包括父任务)发布到TFS中,直接读取TFS中的实时进度
一、COM接口的方式

Code
private void Bind()

{
//Interop Com方式
MSProject.ApplicationClass app = null;
ArrayList taskList = new ArrayList();
try

{
//try
//{
// app = (MSProject.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("MSProject.Application");
//}
//catch (Exception ex)
//{
// //
//}

// execute the Microsoft Project Application
app = new MSProject.ApplicationClass();

// Do not display Microsoft Project
app.Visible = false;

// open the project file.
app.FileOpen(mppFileName, true, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, MSProject.PjPoolOpen.pjPoolReadOnly, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

// go through all the open projects--there should only be one
foreach (MSProject.Project proj in app.Projects)

{
// go through all the tasks in the project
foreach (MSProject.Task task in proj.Tasks)

{
ProTask proTask = new ProTask();
int iTaskLevel = task.OutlineLevel;
for (int j = 0; j < iTaskLevel; j++)

{
proTask.TaskName += " ";
}
proTask.TaskName += task.Name;
proTask.StartDate = Convert.ToDateTime(task.Start);
proTask.FinishDate = Convert.ToDateTime(task.Finish);

//项目进度从TFS服务器中取得
//proTask.PCT = task.PercentComplete.ToString() + "%";
proTask.PCT = GetPCTFromTFS(task.Text10);

proTask.Resources = task.ResourceNames;
taskList.Add(proTask);
}
}

gvTask.DataSource = taskList;
gvTask.DataBind();
}
catch (Exception ex)

{
throw ex;
}
finally

{
if (app != null)

{
app.Quit(MSProject.PjSaveType.pjDoNotSave);
}
}
}

private string GetPCTFromTFS(string id)

{
if (string.IsNullOrEmpty(id))

{
return "";
}
string strSql = "Select [Microsoft.VSTS.Scheduling.RemainingWork],[Microsoft.VSTS.Scheduling.CompletedWork],[Microsoft.VSTS.Scheduling.TaskHierarchy] from workitems where id=" + id;
WorkItemStore Store = new WorkItemStore(tfsServer);
WorkItemCollection wicollection = Store.Query(strSql);
if (wicollection.Count > 0)

{
float RemainingWork = Convert.ToSingle(wicollection[0]["Microsoft.VSTS.Scheduling.RemainingWork"]);
float CompletedWork = Convert.ToSingle(wicollection[0]["Microsoft.VSTS.Scheduling.CompletedWork"]);
if ((int)CompletedWork == 0)

{
return "0%";
}
else if ((int)RemainingWork == 0)

{
return "100%";
}
else

{
float Rate = CompletedWork / (CompletedWork + RemainingWork);
Rate = Rate * 100;
string strRate = Convert.ToString(Rate);
if (strRate.Length > 2)

{
strRate = strRate.Substring(0, 2);
}
return strRate + "%";
}
}

return "";
}
这种方式我就不具体说了,可以看代码中的注释。采用这种方式有几个问题:
速度比较慢;b/s结构时有点问题;
经常报错:
异常详细信息: System.Runtime.InteropServices.COMException: 消息筛选器显示应用程序正在使用中。试了一些解决方案,好像都不行的。
二、直接读取TFS的方式
主意思路是:在TFS中定制一个新的工作项类型,其中包含一个新的工作项字段(项目分解结构);设置Project和TFS之间同步哪些字段,把新的字段包含进去;在Project中使用这个新的工作项类型;使用TFS SDK读出进度情况。
主要分成以下几个步骤进行:
(以下的command命令都是在VS2005命令提示窗口输入的)、
1、加入新的工作项类型
用以下命令导出原有的工作项类型:
然后编辑这个xml文件,以下文件中红色的部分是修改的地方:

工作项类型
<?xml version="1.0" encoding="utf-8"?>
<witd:WITD application="Work item type editor" version="1.0" xmlns:witd="http://schemas.microsoft.com/VisualStudio/2005/workitemtracking/typedef">
<WORKITEMTYPE name="进度">
<DESCRIPTION>包括在整个 MSF Agile 生命周期内跟踪进度的信息</DESCRIPTION>
<FIELDS>
<FIELD name="标题" refname="System.Title" type="String" reportable="dimension">
<HELPTEXT>此进度的简短描述,用于在列表或报告中区分它。</HELPTEXT>
<REQUIRED />
</FIELD>
<FIELD name="状况" refname="System.State" type="String" reportable="dimension">
<HELPTEXT>此进度的工作流状态</HELPTEXT>
</FIELD>
<FIELD name="修订" refname="System.Rev" type="Integer" reportable="dimension" />
<FIELD name="更改者" refname="System.ChangedBy" type="String" reportable="dimension">
<VALIDUSER />
</FIELD>
<FIELD name="问题" refname="Microsoft.VSTS.Common.Issue" type="String" reportable="dimension">
<HELPTEXT>用于突出显示进度,例如,将其标记为问题</HELPTEXT>
<REQUIRED />
<ALLOWEDVALUES expanditems="true">
<LISTITEM value="是" />
<LISTITEM value="否" />
</ALLOWEDVALUES>
<DEFAULT from="value" value="否" />
</FIELD>
<FIELD name="状态更改日期" refname="Microsoft.VSTS.Common.StateChangeDate" type="DateTime">
<WHENCHANGED field="System.State">
<SERVERDEFAULT from="clock" />
</WHENCHANGED>
<WHENNOTCHANGED field="System.State">
<READONLY />
</WHENNOTCHANGED>
</FIELD>
<FIELD name="激活日期" refname="Microsoft.VSTS.Common.ActivatedDate" type="DateTime" reportable="dimension">
<WHENNOTCHANGED field="System.State">
<READONLY />
</WHENNOTCHANGED>
</FIELD>
<FIELD name="激活者" refname="Microsoft.VSTS.Common.ActivatedBy" type="String" reportable="dimension">
<WHENNOTCHANGED field="System.State">
<READONLY />
</WHENNOTCHANGED>
</FIELD>
<FIELD name="原因" refname="System.Reason" type="String" reportable="dimension">
<HELPTEXT>此进度处于当前状态的原因</HELPTEXT>
</FIELD>
<FIELD name="指派给" refname="System.AssignedTo" type="String" reportable="dimension">
<VALIDUSER />
</FIELD>
<FIELD name="工作项类型" refname="System.WorkItemType" type="String" reportable="dimension" />
<FIELD name="关闭者" refname="Microsoft.VSTS.Common.ClosedBy" type="String" reportable="dimension">
<WHENNOTCHANGED field="System.State">
<READONLY />
</WHENNOTCHANGED>
</FIELD>
<FIELD name="关闭日期" refname="Microsoft.VSTS.Common.ClosedDate" type="DateTime" reportable="dimension">
<WHENNOTCHANGED field="System.State">
<READONLY />
</WHENNOTCHANGED>
</FIELD>
<FIELD name="级别" refname="Microsoft.VSTS.Common.Rank" type="String" reportable="dimension">
<HELPTEXT>用于确定工作优先级别的堆栈级别</HELPTEXT>
</FIELD>
<FIELD name="项目分解结构" refname="Microsoft.VSTS.Scheduling.WBS" type="String" reportable="dimension">
<HELPTEXT>项目分解结构</HELPTEXT>
</FIELD>
<FIELD name="创建日期" refname="System.CreatedDate" type="DateTime" reportable="dimension" />
<FIELD name="创建者" refname="System.CreatedBy" type="String" reportable="dimension" />
<FIELD name="集成版本" refname="Microsoft.VSTS.Build.IntegrationBuild" type="String" reportable="dimension">
<HELPTEXT>完成此进度的版本</HELPTEXT>
<SUGGESTEDVALUES expanditems="true">
<LISTITEM value="<无>" />
</SUGGESTEDVALUES>
</FIELD>
<FIELD name="专业领域" refname="Microsoft.VSTS.Common.Discipline" type="String" reportable="dimension">
<HELPTEXT>此进度所属的专业领域</HELPTEXT>
<ALLOWEDVALUES expanditems="true">
<LISTITEM value="开发" />
<LISTITEM value="测试" />
<LISTITEM value="项目管理" />
<LISTITEM value="要求" />
<LISTITEM value="体系结构" />
<LISTITEM value="发布管理" />
</ALLOWEDVALUES>
</FIELD>
<FIELD name="剩余工作" refname="Microsoft.VSTS.Scheduling.RemainingWork" type="Double" reportable="measure" formula=