第18章任务管理系统的设计与实现_第1页
第18章任务管理系统的设计与实现_第2页
第18章任务管理系统的设计与实现_第3页
第18章任务管理系统的设计与实现_第4页
第18章任务管理系统的设计与实现_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

18WindowsForms的任务管理系统。系统总、首次启动任务管理系统时会显示如图18.1所示的主界面该界面包含菜单、、任务列

18.1任务列表显示了当前要完成的任务选中一个任务将在任务详细信息窗口中显示当用户单击上的“任务图”按钮后,将在窗口上显示任务的图视图,如18.2图18.2任务图视图提供了直观的任务完成进度的图表表示形式通过使用图任务执行人员可18.3所示。18.4所示。图18.3添加/编辑任务窗 图18.4资源列表窗列表窗口右侧的笔形图标允许用户单击进行编辑或者用户也可以单击上“添18.5所示。18.518.6所示。图18.6任务类别列表窗 图18.7添加/编辑类别窗数据库系统使用微软的SQLServer或者是SQLExpress进行数据,并且使用EntityFramework来创建实体模型,整个系统由四个数据表组成:TaskTaskResource表:保存与任务相关联的资源列表。18.8所示。18.8任务管理系统数据库关系18.1Resouce资源表字段描字段名字段类值描NN资源名N资源地Y资源代Y18.2Category任务分类表字段描字段名字段类描NN分类名Y18.3TaskResource任务资源表字段描字段名字段类值描NN课程名18.4Task字段名字段类值描NY父项任务N任务标NN任务时N时长类N开始日N结束日NY过期日NY任务类别NNN任务标TaskManager.mdfDatabase文件夹中,程序员可以在VisualStudio中直接创建数据库,步骤如下:18.9所示。18.9添加基于数务的数据库文TaskManager.mdf文件,VisualStudio将弹出服务项,VisualStduio18.10所示。nullnull值。 图18.10表设计器窗 图18.11添加表窗18.11所示。18.12所示。18.12使用拖放的方式设置表的主外键关服务器资源管理器还提供了视图、过程等节点,允许用户直接在VisualStudio中创建过程和视图,不需要在开发机器上安装SQLServer版,增强开发的效率。使用EntityFramework生成实EntityFramework是微软基于ADO.NET技术所发展出来的对象关系映射(O/RMap)解决方案,早期被称为ObjectSpace,在过去,程序员总是与数据库不可分SQL语句,程序员要学习各种数据库的SQL来实现数据库的,ORM对象关系映射技术由此而生,NHibernate是.NET平台下的用于实现ORM的热门工具,微软公司自然不甘,推出了ADO.NETEntityFramework框架。EntityFramework利用了抽象化数据结构的方式,将每个数据库对象都转换成应用程序对象(entity),而数据字段都转换为属性(property),关系则转换为结合属性(association),让数据库的E/R模型完全的转成对象模型,因此能让程序员用最熟悉的编程语言来调用。而在抽象化的结构之下,则是高度集成与对应结构的概念层、对应层和层,以及支持EntityFramework的数据提供者(provider),让数据的工作得以顺利与完整的进行,ADO.NETEntityFramework18.13所示。Database文件夹,在弹出的菜单中选择“添加|新建项”菜单项,在添加新项窗口钮,VisualStudio8.14所示。图18.13ADO.NETEntityFramework框架架 图8.14实体数据模型向导窗列出了数据库中的表、视图和过程等信息,选中要加入到实体数据模型中的表,如图18.15在选择完成后,单击“完成”按钮,VisualStudio将进入到edmx实体数据模型18.16所示。图18.15选择数据库对象窗 图18.16实体模型设计视17.5.1用户界面直接与用户交互,用户通常对一个软件的初始印象的好与坏与良好的用户界WndwsorsDI主窗口IsMdiContainerTrue,在主窗口中放了18.17所示。Strip控ToolStripMDI子窗18.1718.18所示。18.18ToolStrip项集合编辑中通过调用OpenChildForm()方法来实现任务面板的显示,Shown处理及相关的OpenChildForm()18.1所示。代码代码 主窗口//主窗口显示Shown时 处理代privatevoidMainFormShown(objectsender,EventArgs{ //使用OpenTaskForm()}//////打开任务窗口辅助方///privatevoid{if(_taskForm==null||{_taskFormnew }//调用通用的OpenChildForm()方法打开子窗口}/////////paramname="childForm">子窗口Form实例</param>privatevoidOpenChildForm(FormchildForm){childForm.MdiParent //设置MDIchildForm.WindowState=FormWindowState. }OpenTaskFormOpenChildForm()方法创建子窗口实例,这个方法是一个通FormForm基类派生MdiParentMDI容器中进行创建。任务管理窗ComboBox控件提允许用户进18.19所示。DataGridView控

用户控18.19任务面板窗在任务窗口显示时,Shown触发,在处理代码中完成了数据从数据库的加载ShownLoadTaskList()DataGridViewTaskViewer控件中填入要显示的任务数据。BindDropDowns18.2所示。//////向提供选择参数的下拉列表框填入数/////////向提供选择参数的下拉列表框填入数///privatevoid{bo(cmbStatus, , }所有Utility类中的Bindxxx方法都是用于将定义在公共单元中的任务参数枚举值与EntityComboBox控18.3所示。 代码 /////////绑定到任务分类下拉列表///privatevoid{TaskManagerEntitiestaskMgrEntitynewTaskManagerEntities();//实例化EDM模////使用ToList方法将ObjectQuery<Category>转换为泛型列表List<Category>categoryListtaskMgrEntity.Category.ToList();为了 boBox中插入一个空白列,实例化一个新的CategorynewCategory=newcategoryList.Insert(0,newCategory); //将该Category插入到列表第1行 boBox的绑定到的显示成员与值成员 yMember="Name";cmbCategory.ValueMember="CategoryID";//指定其DataSource为返回的List<Category>cmbCategory.DataSource=}EntityFrameworkSystem.Data.Objects.ObjectQuery<T>泛型类型,ObjectQuery执行查询前,必须要实例化ObjectContext,这个对象提供了连接和元数据信息,一个对象查询在下面的将该值赋给List<T>CategoryComboBox中的Category1行,因为没有为Category进行任何赋值,所以将会在ComboBox列表框上显示一个空行。最后指定ComboBox的DisyMember显示为分类名称,而下值为CategoryID,用户可以通过ComboBox.SelectedValueComboBoxDataSource属性后,绑加载任务列TaskViewer控件显示详细的任务信息,LoadTaskList18.4 代码 LoadTaskList方法加载任务列 /////////加载任务列///publicvoid{//实例化ObjectContext的派生TaskManagerEntitiestaskMgrEntitynewTaskManagerEntities();stringwhereClause = if {//查询Task表,并在导航属性中包含CategorygvTasks.DataSource=}{//查询Task表,并在导航属性中包含Category和ResourcegvTasks.DataSource=}if(gvTasks.Rows.Count>{gvTasks.Rows[0].Selected=true;}}LoadTaskListTask,以及与CategoryResourceTaskManageEntities这个ObjectContextGetWhereClauseLINQwhere查询语句。为了让界面AutoGenerateColumnsfalse来手动的在项集合编辑器Category表中的数据。如果用户选择了要过滤的参数,比如任务类别或TaskCategoryResourcewhere进行查gvTasks.DataSource属性设置为查询的结果后,DataGridView将显示任务列表01LoadSelectedTaskDetail填充TaskViewer控件,用来显示任务详细信息。where18.5 代码 GetWhereClause方法生成where语 /////////根据控件的选择生成where语///privatestring{stringwhereClause=ifif(cmbPriority.SelectedIndex>{//使用ConcatWhereClause连接操作符(AND/OR)whereClause=ConcatWhereClause(whereClause,"it.Priority='"+cmbPriority.Text+"'",string.Empty);}ifcmbStatus.SelectedIndex {//查询Status,并连接ANDwhereClause=ConcatWhereClause(whereClause,"it.Status='"+cmbStatus.Text+"'","AND");}ifcmbCategory.SelectedIndex {whereClause=ConcatWhereClause(whereClause,"it.Category.CategoryID="}ifcmbColorCategory.SelectedIndex {whereClause=ConcatWhereClause(whereClause,"it.ColorCategory='"cmbColorCategory.TextAND");//查询ColorCategory}ifcmbFlag.SelectedIndex {whereClause=ConcatWhereClause(whereClause,"it.FlagcmbFlag.TextAND");//查询Flag}return //返回where}在EntityFramework指定it表示查询源自身Task数据源GetWhereClause方法中,总是判断ComboBox控件的SelectedIndex属性是否选择了非0值,然后调用ConcatWhereClausewhere语句,然后是条件、值,AND或OR语句。了Task类相关的Category类的CategoryID进行查询。也就是说总是可以与it指定的格式化DataGridView控FormatGridRowDataGridView的行样式,这个方法的存在是为了让不同状 代码 FormatGridRow方法格式化DataGridView样 ////////////privatevoid{foreach(DataGridViewRowgridRowin{//通过DataGridViewRow绑定的DataBoundItem对象得到TaskTasktask=gridRow.DataBoundItemasTask;StringstringValue //获取Task状态字符if{TaskStatusstatusTaskStatus)Enum.Parseif(status{newFont(gvTasks.RowsDefaultCellStyle.Font,}{}}}}DataGridView控件的每一行是一个DataGridViewRow对象,当将DataGridView的DataBoundItemDataRow对象实例。代码中通过循环遍历DataGridView.Rows集合使用DataGridViewRow.DataBoundItem获取Task对象,将Task的Status属性通过Enum.Parse方法转换为TaskStatus枚举类型的 殊的样式,以区别其他的任务,已完成的任务在DataGridView中的显示效果如图18.20所18.20加载所选的Task详细LoadSelectedTaskDetailTaskTaskViewer用户控件中的控件,TaskViewer控件接收一个Task对象来填充自身,因此当选中第1行时,LoadSelectedTaskDetail方法将从DataGridViewRowDataBoundItemTaskSetTaskDetail18.7所示。 代码 ////////////privatevoid{if(gvTasks.SelectedRows!=nullgvTasks.SelectedRows.Count0)//{//DataBoundItem中获取TaskTasktask=gvTasks.SelectedRows[0].DataBoundItemasTask; //调用SetTaskDetail方法显示任务详细信息}}DataGridView的SelectedRows是否不为null,即是否选中了值,并且DataGridView控件的SelectedRows集合的总数要大于0SelectedRows[0]这个DataGridViewRow对象中获取DataBoundItem对象,强制转换为Task类型,调用TaskViewer控件的SetTaskDetailTask进行显示。使用CellFormatting格式化单元时将使用Task相应的属性来设置DataGridViewImageColumn中要显示的图像。DataGridView18.21的所示。18.21DataGridView列定义中的图像为了能在图像列中显示定制的图像,DataGridView的CellFormating在需要对单元各进行格式化时产生,通过响应该,可以定制DataGridView单元格的外观,处理18.8所示。代码代码 DataGridView的privatevoid{DataGridViewColumncolumn=if{}elseif{ }elseif{ }}CellFormatting的DataGridViewCellFormattingEventArgs类型的参数e包含了要格式化的单元格的一些信息,比如当前单元格的行或列的索引值,分别是ColumnIndex和RowIndex属性,CellStyle用来设置当前单元格的样式。如果单元格成功格式化,可以设置FormattingApplied属性。e.ColumnIndexDataGridViewColumn对象,通过比较列3个列的值其实是枚举类型,因此这几个方法主要是根据在列值转换后FormatPriorityCell方法为18.9所示。 代码 /////////格式化优先级单元///{StringstringValue=e.Valueasstring;//确保返回值为一个字符串类型if(stringValue==null)return; //DataGridViewCellcell=gvTasks[e.ColumnIndex,e.RowIndex];cell.ToolTipText=stringValue; switch {case //从资源中取出最高优先级的Bitmap对e.Value=Properties.Resources.HighPriority;case e.Value=Properties.Resources.LowPriority;case //从资源中取出中等优先级的Bitmap对e.Value=Properties.Resources.MediumPriority; e.Value=Properties.Resources.Empty;}}转换为字符串形式以便进行判断,然后将单元格的值设置为DataGridViewCell的ToolTipText属性,使得能在鼠标悬停在单元格上时,在提示信息中显示单元格的值,接下来使用一个switch语句块,根据不同的值内容向单元格的Value属性赋从资源中提取的BitmapDataGridViewCell中显示图像。Properties.Resource强类型的资源类来查找资源,18.22所示。18.22VisualStudio2010ResourceResourceManager类来从资源中提取资显示任务详细信判断用户是否单击了编辑列来显示一个添加任务窗口,CellClick处理如代码18.10所代码代码 privatevoidgvTasks_CellClick(objectsender,DataGridViewCellEventArgs{ife.RowIndex0&&e.ColumnIndex {DataGridViewColumncolumn=ifcolumn.Name //判断列名是否为{//从DataBoundItem中获取Task对Tasktask=gvTasks.Rows[e.RowIndex].DataBoundItemasTask;if(task!=null){//ShowAddTaskForm方法传入任务ID}}}}CellClickDataGridViewCellEventArgs类型的参数包含当前单击的行列索引,通过使DataGridViewRow的DataBoundItemTask对象实添加/编辑任务窗AddTaskForm窗口,或者用户从工具AddTaskForm窗口。任务编辑窗口提供了一系据库交互,将更改或添加结果保存回数据库,AddTaskForm18.23所18.23添加/ComboBox控件来允许用户输入或者是选择,户是要新建一个任务,否则将根据传入的参数查找Task对象实例来初始化窗口,窗口的重18.11所示。 代码 AddTaskForm重载的构造函 /////////重载构造函数,接收一个任务ID///publicAddTaskForm(int{();//_taskID //如果任务ID0,表示为新增操作,不允许进行删btnDelete.Visible=(taskID>if(taskID>{{//调用LoadTask方法从Task}{}}在代码中,根据传入的TaskID值判断值是否为0,不管是新增或编辑,总是会使用InitFormComboBoxCheckListBox控件填充内容,如18.12所示。 代码 LoadTask方法加载任务到用户界 publicpublicvoid{//GetTask方法从数据库中提取指定ID的TaskTasktask=GetTask(TaskID);if(task!={ inText=if{dtpDueDate.Checked=true;dtpDueDate.Value=task.DueDate.Value;}nudDuration.Value=if(task.Category!=null){cmbCategory.Text=}if(!task.Resource.IsLoaded)foreach(Resourceresourcein{CheckGridResource(resource);//选中CheckBoxList}}}TaskResourceCategoryTask作,利用EntityFramework这种特性可以大大简化传统ADO.NET的实现代码。CheckListBoxSetItemCheckedCheckState状态。使用LINQtoEntity查询任GetTaskLINQTaskIDTask 代码 GetTask方法返回Task对 /////////根据指定的TaskID返回Task对///privateTaskGetTask(int{varmatchs=fromresinwhereres.TaskID==select //LINQ语法查询指定TaskID的Tasktask //调用IQueryable<T>的Firstreturn //Task}ValidateForm方法完成这一过程,该方法返回验证成功与保存按钮处理代码如代码18.14所示。代码代码 保存按privatevoidbtnSaveClick(objectsender,EventArgs{if {Utility.ShowErrorMessage("请提供有效信息.","保存任务错误"); } //调用SaveTaskthis.DialogResult //设置窗口的DialogResult }信息的效果好因为一旦消息框关闭了错误信息也随之用户可能无法所有的错误ErrorProvider会记发生的位置以及具体内容从容的修改错误,直到这些小图标全部,在窗口中ErrorProvider18.24所示。控18.24使有ErrorProvider显示错误消保存任务到数据SaveTask方法将用户在界面中的输入保存回数据库,当然代码需要判断用户是编辑一18.15所示。 代码 SaveTask保存任务到数据 /////////保存或更新任///privatevoid{Tasktask=null;boolisNew=false;if(TaskID>0){task=if(!task.Resource.IsLoaded)}if(task==//保存Task的变//如果是编辑一条//从数据库中获取原始{{task=newisNew=//实例化一个新的Task//指定新增标志为}task.Description= if {task.DueDate=}{task.DueDate=}task.Duration=(int)nudDuration.Value;task.DurationType=cmbDurationType.Text;task.EndDate=GetDateTime(dtpEndDate.Value);plete=(int) task.Priority=cmbPriority.Text;task.ColorCategory=cmbColorCategory.Text;task.Flag=cmbTaskFlag.Text;Categorycategory=if(cmbCategory.SelectedIndex>{//CategoryID的Category//保存Categorycategory=taskMgrEntity.Category.Where("it.CategoryID="+}task.Category=category; //为Task的Category属性赋category对象实例task.StartDate=GetDateTime(dtpStartDate.Value); task.Status=cmbStatus.Text; task.Title //CheckListBox中的选择添加到Task的Resourceif {} }命名用isNew变量来记录新增值,很明显,如果TaskID的值不是等于0的话,那么记GetTaskTask,同时要加载TaskResource集合。对于新增的TaskTaskisNewtrueTaskCategory分类,使用LINQ语法查CategoryIDCategoryIDCategoryTaskCategory属性,SaveResourceCheckListBoxTask.Resource列表中,最后对于新增记录,即isNew为true的Task,调用AddToTask方法将Task添加到ObjectContextTaskSaveChanges方法,该方法将所有的删除选定的任代码代码 删除按privatevoidbtnDeleteClick(objectsender,EventArgs{DialogResultdlgResult","if(dlgResult=={Tasktask=GetTask(TaskID);if(task!=null){//如果Task不为//使用ObjectContext的DeleteObject从实例中删除 this.DialogResult=DialogResult.OK; }}}删除操作会弹出一个确认框,以免用户无意中将Task给删除了,如果用户确认删GetTask方法从数据库中取回TaskObjectContext的DeleteObject任务图窗为了给用户良好的使用体验,任 图窗口提供了以任务时间刻度 图表示GanttChartDataGridView,其实现的技巧在于将图的效果,图的使用效果如图18.25所示。图18.25使用图控件显示任务排,图(Ganttchart)又叫横道图、条状图(Barchart)。它是以图示的方式期发明的,以·L·先生的名字命名,他制定了一个完整地用条形图表进度的标志系统。由于图形象简单,在简单、短期的项目中图都得到了最广泛的运用。为了让图表与Task进行整合,在示例中创建了一个用户控件GanttViewer,该用户,控件由一个DataGridView与图表控件GanttChart组成,在控件内部通过加载Task任务列表交给图控件显示图在TaskGanttChartForm窗口的Load处理代码中,LoadTaskList18.17所示。代码代码 LoadTaskList方法加//////加载任务列///publicvoid TaskManagerEntitiestaskMgrEntity=newTaskManagerEntities();stringwhereClause=GetWhereClause(); ObjectQuery<Tasktasks if{//Task及其关联的Category集tasks=}{//否则调用Where扩展方法进行任务过taskstasks=}List<Task>taskList=newList<Task>();if(tasks!=null)taskList=//通过ToList}TaskResourceCategory的数据,需要首先实TaskManagerEntities这个ObjectContext对象,然后使用GetWhereClause方法从ComboBox控件中提取查询where子句,接下来根据whereClause是否为空来提取数据库中的部分或全部数据,将返回的IQueryable<Task>使用ToList扩展方法转为泛型列表,GanttViewer控件提供了LoadTasks方法接收List<Task>类型的泛型列表来向图与DataGridView控件绑定数据。图视图控件中的DataGridView响应属标双击,在鼠标双击后,将会触发OnTaskOpenEvent,在该的OpenTaskEventArgs类型的参数中,传入了用户双击任务的TaskID值,该处理代码中,调用ShowAddTaskForm方法来显示添加/编辑任务窗资源是指任务可分配的人员信息,资源将被Task用来为特定的任务分配人力,资源中包含名称代码等信息在TaskList的添加/编辑窗口中资源被添加到CheckListBox18.2618.26资源管理窗资源管理窗较固定,因此没有提供用来过滤的ComboBox控件,在资源管理窗口中,只有一个DataGridView控件在ResourceForm窗口的Shown处理代码中调用LoadResourceListDataGridView18.18 代码 LoadResourceList方法加载资 ////////////publicvoid TaskManagerEntitiessqlTaskMgr=newTaskManagerEntities();gvResources.AutoGenerateColumns=false; gvResources.DataSource=sqlTaskMgr.Resource; }TaskManagerEntitiesResource属性查询所有的资源列表,然后绑定DataGridView控件上。DataGridView控件也提供了一个编辑的小图标,用户单击该图标时,将弹出添加/编辑资源窗口,实现这个功能是通过响应DataGridView控件的CellClick来完成的,处理代码如代码18.19所示。代码代码 privatevoidgvResources_CellClick(objectsender,DataGridViewCellEventArgs{if(e.RowIndex>=0&&e.ColumnIndex>={//使用e.ColumnIndex得到当前单击的DataGridViewColumncolumngvResources.Columns[e.ColumnIndex];if(column.Name=="Edit")//如果列名为Edit{ResourceresourcegvResources.Rows[e.RowIndex].DataBoundItemasResource;if(resource!=null){//调用ShowAddResourceForm方法显示添加/}}}}}DataGridViewCellEventArgs类型的参数,获取当前当击的行与列的位置,然ShowAddResourceFormID号来显示添加/编辑窗口。添加资源窗ResourceResource进行编辑,AddResourceForm重载的构造函18.20所示。 代码 AddResourceForm重载的构造函 /////////重载的构造函数,获取资源///paramname="resourceID">资源ID</param>publicAddResourceForm(intresourceID){_resourceID //只有在编辑时才允许删除,判断资源ID的btnDelete.Visible=(resourceID>if(resourceID>0) //如果传入了资源ID }resourceIDID0Resource218.21 代码 LoadResource与GetReousce方法的实现代 ////////////privatevoid{//调用GetResource方法得到指定ID的Resource对Resourceresource=if(resource!={txtName.Text=txtCode.TexttxtCode.Text= Address.Text=resource. inText=resource.ResourceDetail;}}/////////paramname="resourceID">资源///<returns>Resource对象实例</returns>privateResourceGetResource(intresourceID){//从Resource集合中查询指定资源ID的Resourcevarmatchsfromresinwhereres.ResourceID==resourceIDselectres;Resourceresource return //返回Resource}ResourceIDIDResourceFirst扩展方法返回首个Resource对象。LoadResourceResource方法,更新用户界面的显示。使用ErrorProvider控件验证表ValidateForm方法来验证用户的输入,同时因为资源中18.22所示。 代码 ValidateForm方法的实现代 ////////////returns>t如果所有数据有效,返回True</returns>privateboolValidateForm(){boolres=#region验证资源名称是否正if{//设置ErrorProvider的错误信息errorProvider1.SetError(txtName请提供资源名称.");res=false;}{//如果输入正确,则清空ErrorProvider} if {if Address.Text,{//设置ErrorProvider Address请提供有效的电子邮件地址.");res=false;}{//如果设置正确,清空ErrorProvider Address,}}{//否则使得ErrorProvider Address,}return }AddResourceFormErrorProvider来提供友好的错误信息显示,那么对于资源名称为空时,使用ErrorProviderSetErrortxtName控件的错误显示。对于地址在确保用户提供了地址字符串的前提下构造了用来匹配地址的Regex对象,调用Regex.IsMatch方法将txtAddress.Text与Regex进行ErrorProviderstring.Empty。ValidateForm方法被按钮单击处理代码调用,只有在验证通过,才调保存资源到数据SaveResource方法判断当前ResourceID的值,如果值大于0,表示是对一个已存的ResourceResource对象插入到资源列表中,SaveResource方18.23所示。代码 SaveResource方法的实现代////////////privatevoid{Resourceresource=null;boolisNew=false;if(ResourceID>{//从已存的资源中取得特定ID的资resource=}if(resource=={resource=newDatabase.Resource();isNew=true;}//根据用户界出的输入更新Resource的属//如果不存在指定ID//新建一个资源Resource对resource.ResourceName=txtName.Text.Trim(); Address=txt resource.ResourceCode=txtCode.Text.Trim();resource.ResourceDetail=textEditor1. if {//调用AddToResource} }ResourceResource对象后,代码接下来使用用户在界面控件中的输入来更新Resource对象的属性。最后对于新增记录,将调用类型化的AddToResource方法将资源添加到实体集合中,AddToResource方法在内部调用了ObjectContext.AddObject方法向指定的实体集名称添加对象,例如对于添加资源 ObjectContextSaveChanges方法向数据库提交更删除指定的资18.24所示。代码代码 删除按privatevoidbtnDeleteClick(objectsender,EventArgs{ DialogResultdlgResult?","ifdlgResult {//使用GetResource获取当前资源Resourceresource=ifresource //如果资源存在则不为{//使用DeleteObject从实体集中删除该资源对//将当前窗口的DialogResoult设置为this.DialogResult=DialogResult.OK;//关闭窗}}}UtilityShowConfirmationBox方法向用户显示一个删除确认提示框,SaveChanges方法向数据库提交更改完成删TaskCategoryTask是一对多关系,一个Task只能对应一个Category,而一个Category可以被多个Task。任务的添类别管理窗18.27所示。18.27任务类别管理窗在代码中,依然响应了CategoryForm的Shown,在处理代码中,调用了DataGridView18.25所示。 代码 /////////加载所有的任务分类列///publicvoid{TaskManagerEntitiessqlTaskMgr=newTaskManagerEntities();gvCategory.AutoGenerateColumns=false; gvCategory.DataSource=sqlTaskMgr.Category; }代码首先实例化TaskManagerEntities实体上下文对象,将DataGridView控件的AutoGenerateColumnsDataSourceCategory实体集。为了允许用户编辑当前选中的分类,为DataGridView控件添加了一个新的DataGridViewImageColumnDataPropertyName属性,该属性表示要绑定到的目标的属性名称或者是数据字段。当用户单击DataGridView控件时,CellClick触发,在处理代码中将判断名为Edit的列,弹出添加/编辑分类窗口,CellClick处理代码18.26所示。代码代码 DataGridView控件的privatevoidgvCategoryCellClick(objectsender,DataGridViewCellEventArgs{if(e.RowIndex>=0&&e.ColumnIndex>={//根据当前单击的列索引得到DataGridViewColumn实例DataGridViewColumncolumn=gvCategory.Columns[e.ColumnIndex];if(column.Name=="Edit") //如果列名称为Edit{//DataGridViewRow的DataBoundItem属性中得到Category对Categorycategory=DataBoundItemasifcategory //Category不为{}}}}DataGridViewCellEventArgs类型的e包含了RowIndex与ColumnIndex允许用户使2DataGridViewe.ColumnIndex找到了DataGridViewColumnName属性是否为EditDataBoundItemCategoryShowAddCategoryForm方法,传入分类的CategoryID显示添加/编辑分类窗口。添加类别窗0CategoryID0,表示对一个现有的分类Category类别对象,填充到用户界面,重载的构造18.27所示。 代码 /////////重载的构造函数,接收要添加或编辑的类别///paramname="categoryID">类别ID值publicAddCategoryForm(int{{_categoryID=//保存传入的categoryIDbtnDelete.Visible=(categoryID>ifcategoryID }在构造函数中,根据传入的类别ID来确定是否需要显示或隐藏删除按钮,同时如果CategoryID0LoadCategory方法CategoryIDCategory对象,用该对象的属性来更新用户界面。LoadCategoryGetCategoryCategoryIDCategory对象,218.28所示。 代码 LoadCategory加载类别到控 ////////////privatevoid{//从数据库中获取指定CategoryID的Category对Categorycategory=GetCategory(CategoryID);if(category!=null){txtName.Text inText=}}//////根据类别ID获取类///<paramname="categoryID">类别ID号///<returns>返回Category对象</returns>privateCategoryGetCategory(intcategoryID){//查询与指定的CategoryID匹配的Category列varmatchs=fromresintaskMgrEntity.Categorywhereres.CategoryID==categoryIDselectres;Categorycategory return}18.29所示。 代码 SaveCategory方法保存到数据 //////保存/更新分///privatevoid{Categorycategory=null;boolisNew=false;if(CategoryID>{//2个变量用来保存临时数//////保存/更新分///privatevoid{Categorycategory=null;boolisNew=false;if(CategoryID>{//2个变量用来保存临时数//使用GetCategory提取一个Category对category=}if(category=={category=newCategory();isNew=true;}//实例化一个新的Category对category.NametxtName.Text.Trim();//category.Description= if {//使用AddToCategory添加到实体集} }实现图视图用户控DataGridViewGanttChart控件以图图形显示任务的时区跨度,便于程序于进行后期的与修改。GanttViewer控件从UserControl基类派生,程序员可以用户控件模板来创建一个新的用户控件,添加新项窗口18.28所示。18.28使用VisualStudio2010用户控件模UserControlForm表单的设计public级别的属性,同时对于一些需要由调用方执public级别的方法。当用户控件内部发生变化需要通知调用方时,可以通GanttViewer控件提供的方法是LoadTasks方法,该方法接收List<Task>泛型任务18.30所示。代码代码 LoadTasks方法显//////加载任务的公共方///<paramname="tasks">任务列表</param>publicvoidLoadTasks(List<Task>tasks){_taskList=gvTitle.AutoGenerateColumns=gvTitle.DataSource=图}LoadTasksList<Task>ClearData方法清除甘特图中的数据,然后将传入的List<Task>保存到类私有的_taskList变量中,接下来将DataGridView的DataSource属性为List<Task>完成对网格的绑定。绑定到图控GranttChart代码代码 BindGanttChartGrid绑定//////将任务列表保存 ///<paramname="Tasks">任务列表privatevoidBindGanttChartGrid(List<Task>{DataTabledt=newDataTable();DateTime?minDate=GetMiniDate(Tasks);DateTime?maxDate=GetMaxDate(Tasks);if(minDate.HasValue)minDate=minDate.Value.AddDays(-10);if(maxDate.HasValue)maxDate=maxDate.Value.AddDays(10);if(maxDate.HasValue&&{DateTimecolDate=minDate.Value;while(colDate<=maxDate.Value){//实例化一个DataTable对//将最小日期减10//将最大日期加10colDate=colDate.AddDays(1); //1天}}_todayIndex=-foreach(Tasktaskin{DataRowr=dt.NewRow();inti=0;//循环遍历Task列foreach olumncolumnin{DateTimeDateTimecolumnDateConvert.ToDateTime(column.ColumnName得到列上的日期boolbusy=false;if(columnDate>=task.StartDate<=)//busy=true;if(busy){r[i]=}{r[i]=}//busy为//仅在任务可设置时,才设置任务的if(_todayIndex<0&&DateTime.Now.ToShortDateString()=={_todayIndex } //DataRow添加到Rows}gvGantt.DataSource }BindGanttChartGridList<Task>列表中,最小的起始日期与最大的结束日期,这2个日期中间的位置就是图表要显示的刻度区域,图控件的列数将取最小ColumnsDateTime.AddDay方法法逐日进行递加。Tasks泛型集合,在循环体内部,构造DataRowDataRowTaskID,通过比较当Task.StartDateEndDate进行比较,如果列的日是期大于或等于起始日期,busytruebusytrueDataRow的特定的列索引指定值为TaskID。_totalIndex这个类私有的整型变量用来保存当前任务刻度中,该变量在列的日期值是等于今天时,将_totalIndex属性设置为当前列的索引,在绑定完成后,会根据_totalIndex属性指定的索引,调用DataGridView控件的FirstDisyedScrollingColumnIndex方法将首最后通过将图控件的DataSource属性设置为构建的DataTable数据表来实现显示图提示消当用户在图形上悬停鼠标时会在提示中显示当前任务的详细信息如图totalIndex所在

18.29的多数,为了在条形上显示任务详细信息,响应了CellToolTipTextNeeded,该在单元格需要显示提示信息时发生,处理如代码18.32所示。代码代码 privatevoidgvGantt_CellToolTipTextNeeded//在需要显示单元格提示时触发(objectsender,DataGridViewCellToolTipTextNeededEventArgse){//从单元格的值中获取当前的inttaskID=gvGantt.GetCellValue(e.RowIndex,//调用自定义的GetToolTipText方法显示任务详e.ToolTipText=}GetCellValue是在GanttChart控件中定义的一个方法,用来获取单元各的值处理属性返回提示文本,GetToolTipText18.33所示。, 代码 GetToolTipText获取单元格提示文 ,/////////获取工具提示文///paramname="taskID">任务returns>返回工具提示文本</returns>privatestringGetToolTipText(inttaskID){Tasktask //保存TaskstringtoolTip=string.Empty; if(taskID>0){if(_taskList!={{//从_taskList中查询具有指定TaskID的Tasktask=_taskList.Where(t=>t.TaskID==}}iftask //TaskID{toolTip="开始日期:"+task.StartDate.ToShortDateString()+"\n"+"结束日期task.EndDate.ToShortDateStringn"完成百分比:"+ plete.ToString()+"%\n"+"状态:"+task.Status+"\n"+"task.Priority}return }GetToolTipText方法接收整型的TaskID值,因为用户控件的_taskList保存了泛型的方法返回首个对象实例,然后根据Task的属性来构造一个信息提示的字符串,返回给单元GanttViewer_onTaskOpenEvent的,该是OnTaskOpenDelegate委托类型,接收object类型的senderOpenTaskEventArgseDataGridView调用应该,打开任务详细信息窗口。DoubleClick的处理如代码18.34所示。代码代码 privatevoidgvTitleDoubleClick(objectsender,EventArgs{ifgvTitle.SelectedCells.Count {introwIndexgvTitle.SelectedCells[0].RowIndex//TaskTasktask=gvTitle.Rows[rowIndex].DataBoundItemas//Task实例不能为null,且_onTaskOpenEvent需要被实例if(task!=null&&_onTaskOpenEvent!={ ,传入TaskID作 onTaskOpenEvent(gvTitle,new}}}在代码中,通过判断用户选择的单元格得到行索引,然后根据行索引得到Task对象实_onTaskOpenEventTaskIDTaskGanttChartForm.cs中,响应了GanttViewer控件的OnTaskOpenEvent,调用ShowAddTaskForm方法显示添加/编辑任务窗口。实现任务列表用户控属性,如果将属性设置为True,则会显示格式,如图18.30所示。图18.30具有格式化的TextEditor控件呈现效将任务详细信息实现为用户控件只需要对用户控件进行进一步的而不需要对显变,这大大减轻了重复性的工作。TaskViewer控件公开的最重要的是SetTaskDetailTask对象的实18.35所示。 代码 SetTaskDetail方法实现代 /////////加载任务详细信///paramname="task">Task对象实例</param>publicvoidSetTaskDetail(Tasktask){if(task=={}lblTitle.Text=//如果传入一个空Task对//设置标 inText=//lblStartDate.Texttask.StartDate.ToShortDateString();//lblEndDate.Text=task.EndDate.ToShortDateString();lblDuration.Text=task.Duration.ToString()+""+task.DurationType;plete.Text= plete+"%";lblStatus.Text=task.Status;lblPriority.Text=lblDueDate.Text=(task.DueDate.HasValue)?lblCategory.Text=(task.Category!=null)?task.Category.Name://在Label控件上显示与TasklblResources.Te

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论