前期说明:在Project2007中可以选择一个团队项目(TFS),然后在Project2007中排好进度,作为工作项发布到TFS服务器上。之后可以直接作为工作项在VS2005等工具中填写项目进度。本文的目的就是要显示出TFS中保存的实时项目进度情况等。
技术说明:在Project2007之前的版本可以通过oledb的方式直接读取project的mpp文件来显示进度,在project2007时不再提供oledb的方式了,可能的两种实现方法有:
1、使用Project2007提供的COM接口,读取mpp文件中的任务 + TFS中的实时进度
2、把所有的进度安排(包括父任务)发布到TFS中,直接读取TFS中的实时进度
前期说明:在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="sum">
<HELPTEXT>完成此进度还需要的小时数的估计</HELPTEXT>
</FIELD>
<FIELD name="已完成工作" refname="Microsoft.VSTS.Scheduling.CompletedWork" type="Double" reportable="measure" formula="sum">
<HELPTEXT>执行此进度已花费的小时数</HELPTEXT>
</FIELD>
<FIELD name="基线工作" refname="Microsoft.VSTS.Scheduling.BaselineWork" type="Double" reportable="measure" formula="sum">
<HELPTEXT>基线计划中的工作小时数</HELPTEXT>
</FIELD>
<FIELD name="完成日期" refname="Microsoft.VSTS.Scheduling.FinishDate" type="DateTime" reportable="dimension">
<HELPTEXT>完成进度的日期</HELPTEXT>
</FIELD>
<FIELD name="任务层次结构" refname="Microsoft.VSTS.Scheduling.TaskHierarchy" type="String" reportable="dimension">
<HELPTEXT>表示给定进度的 MS-Project 上下文的字符串</HELPTEXT>
</FIELD>
<FIELD name="开始日期" refname="Microsoft.VSTS.Scheduling.StartDate" type="DateTime" reportable="dimension">
<HELPTEXT>开始进度的日期</HELPTEXT>
</FIELD>
<FIELD name="退出条件" refname="Microsoft.VSTS.Common.ExitCriteria" type="String" reportable="dimension">
<HELPTEXT>用于确定是否应将此方案作为迭代的退出条件进行跟踪的标志</HELPTEXT>
<REQUIRED />
<ALLOWEDVALUES expanditems="true">
<LISTITEM value="是" />
<LISTITEM value="否" />
</ALLOWEDVALUES>
<DEFAULT from="value" value="否" />
</FIELD>
<FIELD name="说明" refname="System.Description" type="PlainText" />
<FIELD name="历史记录" refname="System.History" type="History">
<HELPTEXT>讨论线索和其他历史记录信息</HELPTEXT>
</FIELD>
<FIELD name="相关链接计数" refname="System.RelatedLinkCount" type="Integer" />
<FIELD name="迭代路径" refname="System.IterationPath" type="TreePath" reportable="dimension">
<HELPTEXT>与此进度关联的产品迭代</HELPTEXT>
</FIELD>
<FIELD name="迭代 ID" refname="System.IterationId" type="Integer" />
<FIELD name="外部链接计数" refname="System.ExternalLinkCount" type="Integer" />
<FIELD name="团队项目" refname="System.TeamProject" type="String" reportable="dimension" />
<FIELD name="超链接计数" refname="System.HyperLinkCount" type="Integer" />
<FIELD name="附加文件计数" refname="System.AttachedFileCount" type="Integer" />
<FIELD name="节点名称" refname="System.NodeName" type="String" />
<FIELD name="区域路径" refname="System.AreaPath" type="TreePath" reportable="dimension">
<HELPTEXT>与此进度关联的产品区域</HELPTEXT>
</FIELD>
<FIELD name="修订日期" refname="System.RevisedDate" type="DateTime" />
<FIELD name="更改日期" refname="System.ChangedDate" type="DateTime" reportable="dimension" />
<FIELD name="ID" refname="System.Id" type="Integer" reportable="dimension" />
<FIELD name="区域 ID" refname="System.AreaId" type="Integer" />
<FIELD name="更改用户 " refname="System.AuthorizedAs" type="String" />
</FIELDS>
<WORKFLOW>
<STATES>
<STATE value="活动的">
<FIELDS>
<FIELD refname="Microsoft.VSTS.Common.ClosedDate">
<EMPTY />
</FIELD>
<FIELD refname="Microsoft.VSTS.Common.ClosedBy">
<EMPTY />
</FIELD>
</FIELDS>
</STATE>
<STATE value="已关闭" />
</STATES>
<TRANSITIONS>
<TRANSITION from="" to="活动的">
<REASONS>
<DEFAULTREASON value="新的" />
</REASONS>
<FIELDS>
<FIELD refname="Microsoft.VSTS.Common.ActivatedBy">
<COPY from="currentuser" />
<VALIDUSER />
<REQUIRED />
</FIELD>
<FIELD refname="Microsoft.VSTS.Common.ActivatedDate">
<SERVERDEFAULT from="clock" />
</FIELD>
<FIELD refname="System.AssignedTo">
<DEFAULT from="currentuser" />
</FIELD>
</FIELDS>
</TRANSITION>
<TRANSITION from="活动的" to="已关闭">
<REASONS>
<DEFAULTREASON value="已完成" />
<REASON value="已推迟" />
<REASON value="已过时" />
<REASON value="剪切" />
</REASONS>
<FIELDS>
<FIELD refname="Microsoft.VSTS.Common.ClosedDate">
<SERVERDEFAULT from="clock" />
</FIELD>
<FIELD refname="Microsoft.VSTS.Common.ClosedBy">
<COPY from="currentuser" />
<VALIDUSER />
<REQUIRED />
</FIELD>
<FIELD refname="Microsoft.VSTS.Common.ActivatedBy">
<READONLY />
</FIELD>
<FIELD refname="Microsoft.VSTS.Common.ActivatedDate">
<READONLY />
</FIELD>
</FIELDS>
<ACTIONS>
<ACTION value="Microsoft.VSTS.Actions.Checkin" />
</ACTIONS>
</TRANSITION>
<TRANSITION from="已关闭" to="活动的">
<REASONS>
<DEFAULTREASON value="已重新激活" />
</REASONS>
<FIELDS>
<FIELD refname="Microsoft.VSTS.Common.ActivatedBy">
<COPY from="currentuser" />
<VALIDUSER />
<REQUIRED />
</FIELD>
<FIELD refname="Microsoft.VSTS.Common.ActivatedDate">
<SERVERDEFAULT from="clock" />
</FIELD>
<FIELD refname="System.AssignedTo">
<COPY from="field" field="Microsoft.VSTS.Common.ClosedBy" />
</FIELD>
</FIELDS>
</TRANSITION>
</TRANSITIONS>
</WORKFLOW>
<FORM>
<!-- Guidelines for updating the form section
1) All labels should have mnemonics (you must use & not just &)
2) No mnemonics on Tabs or Group Boxes
3) Labels must use sentence casing (i.e. "Assigned to:" is correct; "Assigned To:" is wrong)
4) No colons in Group Boxes
5) Label names should match the field name in whole or in part. They should not be completely different.
6) Do not use the same mnemonics on two labels
The following mnemonics are common to MSF Agile work items:
T -> Title
A -> Area
I -> Iteration
G -> Assigned to
S -> State
R -> Reason
H -> Comment and history
U -> Issue
B -> Integration build
C -> Description
E -> Start Date
F -> Finish Date
The following mnemonics are also used on this work item type
D -> Discipline
K -> Rank
X -> Exit criteria
W -> Remaining work
P -> Completed work
O -> Task Context
-->
<Layout>
<Group>
<Column PercentWidth="70">
<Control Type="FieldControl" FieldName="System.Title" Label="标题(&T):" LabelPosition="Left" />
</Column>
<Column PercentWidth="30">
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Common.Discipline" Label="准则(&D):" LabelPosition="Left" />
</Column>
</Group>
<Group Label="分类">
<Column PercentWidth="100">
<Control Type="WorkItemClassificationControl" FieldName="System.AreaPath" Label="区域(&A):" LabelPosition="Left" />
<Control Type="WorkItemClassificationControl" FieldName="System.IterationPath" Label="迭代(&I):" LabelPosition="Left" />
</Column>
</Group>
<Group Label="状态">
<Column PercentWidth="50">
<Control Type="FieldControl" FieldName="System.AssignedTo" Label="指派给(&G):" LabelPosition="Left" />
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Common.Rank" Label="级别(&K):" LabelPosition="Left" NumberFormat="WholeNumbers" MaxLength="10" />
</Column>
<Column PercentWidth="50">
<Control Type="FieldControl" FieldName="System.State" Label="状态(&S):" LabelPosition="Left" />
<Control Type="FieldControl" FieldName="System.Reason" Label="原因(&R):" LabelPosition="Left" />
</Column>
</Group>
<TabGroup>
<Tab Label="说明">
<Control Type="HtmlFieldControl" FieldName="System.Description" Label="说明(&C):" LabelPosition="Top" Dock="Fill" />
</Tab>
<Tab Label="历史记录">
<Control Type="WorkItemLogControl" FieldName="System.History" Label="历史记录(&H):" LabelPosition="Top" Dock="Fill" />
</Tab>
<Tab Label="链接">
<Control Type="LinksControl" />
</Tab>
<Tab Label="文件附件">
<Control Type="AttachmentsControl" />
</Tab>
<Tab Label="详细信息">
<Group>
<Column PercentWidth="50">
<Group Label="常规">
<Column PercentWidth="100">
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Common.Issue" Label="问题(&U):" LabelPosition="Left" />
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Common.ExitCriteria" Label="退出条件(&X):" LabelPosition="Left" />
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Build.IntegrationBuild" Label="集成版本(&B):" LabelPosition="Left" />
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Scheduling.TaskHierarchy" Label="进度上下文(&O):" LabelPosition="Left" ReadOnly="True" />
</Column>
</Group>
</Column>
<Column PercentWidth="50">
<Group Label="安排">
<Column PercentWidth="100">
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Scheduling.RemainingWork" Label="剩余工作(小时)(&W):" LabelPosition="Left" NumberFormat="DecimalNumbers" MaxLength="10" />
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Scheduling.CompletedWork" Label="已完成工作(小时)(&P):" LabelPosition="Left" NumberFormat="DecimalNumbers" MaxLength="10" />
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Scheduling.StartDate" Label="开始日期(&E):" LabelPosition="Left" ReadOnly="True" />
<Control Type="FieldControl" FieldName="Microsoft.VSTS.Scheduling.FinishDate" Label="完成日期(&F):" LabelPosition="Left" ReadOnly="True" />
</Column>
</Group>
</Column>
</Group>
</Tab>
</TabGroup>
</Layout>
</FORM>
</WORKITEMTYPE>
</witd:WITD>
然后用以下命令把它加入到tfs中去:
witimport /f "E:\\scheduletask.xml" /t "http://server:8080/" /p projectname
这样我们就增加了一个新的工作项类型:进度,和一个新的工作项字段:Microsoft.VSTS.Scheduling.WBS
2、确定TFS和project之间可以同步哪些字段
首先下载原有配置:
TFSFieldMapping.exe download http://server:8080 projectname "E:\MappingFile.xml"
在原有配置上修改,见红色部分:

TFS配置
<?xml version="1.0" encoding="utf-8"?>
<MSProject>
<Mappings>
<Mapping WorkItemTrackingFieldReferenceName="System.Id" ProjectField="pjTaskText10" ProjectName="工作项 ID"/>
<Mapping WorkItemTrackingFieldReferenceName="System.Title" ProjectField="pjTaskName"/>
<Mapping WorkItemTrackingFieldReferenceName="System.WorkItemType" ProjectField="pjTaskText24"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Common.Discipline" ProjectField="pjTaskText17"/>
<Mapping WorkItemTrackingFieldReferenceName="System.AssignedTo" ProjectField="pjTaskResourceNames"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Scheduling.CompletedWork" ProjectField="pjTaskActualWork" ProjectUnits="pjHour"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Scheduling.RemainingWork" ProjectField="pjTaskRemainingWork" ProjectUnits="pjHour"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Scheduling.BaselineWork" ProjectField="pjTaskBaselineWork" ProjectUnits="pjHour"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Scheduling.StartDate" ProjectField="pjTaskStart" PublishOnly="true"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Scheduling.FinishDate" ProjectField="pjTaskFinish" PublishOnly="true"/>
<Mapping WorkItemTrackingFieldReferenceName="System.State" ProjectField="pjTaskText13" ProjectName="状况"/>
<Mapping WorkItemTrackingFieldReferenceName="System.Reason" ProjectField="pjTaskText14"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Common.Rank" ProjectField="pjTaskText16"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Common.Issue" ProjectField="pjTaskText15"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Common.ExitCriteria" ProjectField="pjTaskText20"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Common.QualityOfServiceType" ProjectField="pjTaskText21"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Common.RoughOrderOfMagnitude" ProjectField="pjTaskText22"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Common.Priority" ProjectField="pjTaskText19" ProjectName="工作项优先级别"/>
<Mapping WorkItemTrackingFieldReferenceName="System.AreaPath" ProjectField="pjTaskOutlineCode9"/>
<Mapping WorkItemTrackingFieldReferenceName="System.IterationPath" ProjectField="pjTaskOutlineCode10"/>
<Mapping WorkItemTrackingFieldReferenceName="System.Rev" ProjectField="pjTaskText23"/>
<Mapping WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Scheduling.WBS" ProjectField="pjTaskWBS" PublishOnly="true"/>
<ContextField WorkItemTrackingFieldReferenceName="Microsoft.VSTS.Scheduling.TaskHierarchy"/>
<LinksField ProjectField="pjTaskText26"/>
<SyncField ProjectField="pjTaskText25"/>
</Mappings>
</MSProject>

再把配置文件上传:
TFSFieldMapping.exe upload http://server:8080 projectname "E:\MappingFile.xml"
这样就把TFS字段和project中的指定字段对应起来了
三、在project中使用"进度"工作项类型
这一步比较简单,就是在project中选择团队项目,排计划时选择"进度"类型,然后发布到tfs中就可以了
四、使用tfs SDK读取进度
就是使用TFS SDK就可以了:
private void BindTfs()

{
ArrayList taskList = new ArrayList();

StringBuilder sbSql = new StringBuilder();
sbSql.Append("Select [Microsoft.VSTS.Scheduling.RemainingWork],[Microsoft.VSTS.Scheduling.CompletedWork]");
sbSql.Append(",[System.Title]");
sbSql.Append(",[System.AssignedTo]");
sbSql.Append(",[Microsoft.VSTS.Scheduling.StartDate]");
sbSql.Append(",[Microsoft.VSTS.Scheduling.FinishDate]");
sbSql.Append(",[Microsoft.VSTS.Scheduling.WBS]");
sbSql.Append(" from workitems where [System.WorkItemType]='进度' ");
sbSql.Append(" order by [Microsoft.VSTS.Scheduling.WBS]");
WorkItemStore Store = new WorkItemStore(tfsServer);
WorkItemCollection wicollection = Store.Query(sbSql.ToString());
foreach (WorkItem item in wicollection)

{
ProTask proTask = new ProTask();

//当前进度
string strRate = "";
float RemainingWork = Convert.ToSingle(item["Microsoft.VSTS.Scheduling.RemainingWork"]);
float CompletedWork = Convert.ToSingle(item["Microsoft.VSTS.Scheduling.CompletedWork"]);
if ((int)CompletedWork == 0)

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

{
strRate = "100%";
}
else

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

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

proTask.TaskName = item.Title;
proTask.StartDate = Convert.ToDateTime(item["Microsoft.VSTS.Scheduling.StartDate"]);
proTask.FinishDate = Convert.ToDateTime(item["Microsoft.VSTS.Scheduling.FinishDate"]);
proTask.Resources = item["System.AssignedTo"].ToString();
proTask.WBS = item["Microsoft.VSTS.Scheduling.WBS"].ToString();
taskList.Add(proTask);
}


gvTask.DataSource = taskList;
gvTask.DataBind();
}
附:
在浏览所有进度时出现问题:拒绝访问(The work item does not exist, or you do not have permission to access it. )
原因:tfs装的是90天测试版,在过期时把日期改为之前两个月了,导致进度这个工作项的加入时间和系统时间有冲突,将系统时间改为工作项加入之后的时间,重启iis就可以了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?