DevExpress Winforms使用技巧教程:甘特圖控件中的自定義繪圖
DevExpress Winforms Controls 內置140多個UI控件和庫,完美構建流暢、美觀且易于使用的應用程序。無論是Office風格的界面,還是分析處理大批量的業(yè)務數(shù)據(jù),DevExpress WinForms都能輕松勝任。DevExpress廣泛應用于ECM企業(yè)內容管理、 成本管控、進程監(jiān)督、生產調度,在企業(yè)/政務信息化管理中占據(jù)一席重要之地。
【適用范圍】:各種桌面、Web應用程序開發(fā),尤其是WinForms應用程序開發(fā)。
在日前正式發(fā)布的DevExpress v19.2中,DevExpress WinForms Gantt Control已作為社區(qū)技術預覽(CTP)正式發(fā)布!從此版本到將來的v20.1版本,技術團隊將改進和擴展此控件,以便您無需編寫代碼即可提供出色的用戶體驗!本文將介紹如何利用甘特圖控件的CustomDraw事件來模擬與甘特圖相關的主要功能。
Custom Draw事件
DevExpress WinForms Gantt控件包含以下Custom Draw事件:
- CustomDrawTask - 允許您在控件的Diagram區(qū)域內手動繪制標準任務、摘要任務和里程碑。
- CustomDrawTaskDependency - 使用此事件來自定義任務依賴性(從一個任務欄指向另一個任務欄的箭頭)。
- CustomTaskDisplayText - 允許您自定義任務標題。
- CustomDrawTimescaleColumn - 允許您自定義Diagram面板的工作區(qū)域。
通過組合這些事件,您可以引入尚未集成到控件中的功能(繪制關鍵路徑、拆分任務、指定截止日期等)。
關鍵路徑
關鍵路徑是一系列非常重要的項目任務,它們之間的延遲為零。 如果您準備好將WinForms Gantt集成到軟件項目中,并且等不及下一次重大更新,則可以結合使用CustomDrawTask和CustomDrawDependency事件來手動突出顯示與關鍵路徑關聯(lián)的任務欄以及連接它們的箭頭。
注意:在此代碼示例和其他代碼示例中,使用skin colors突出顯示元素,這些顏色會根據(jù)當前應用的皮膚略微改變色調。
HashSet<int> criticalPathIds = new HashSet<int> { 1, 2, 3, 6, 7, 8, 10, 11, 13 }; ganttControl.CustomDrawTask += (sender, e) => { int taskId = Convert.ToInt32(e.Node.GetValue("Id")); if(criticalPathIds.Contains(taskId)) { e.Appearance.BackColor = DXSkinColors.FillColors.Danger; e.Appearance.ProgressColor = DXSkinColors.FillColors.Danger; } }; ganttControl.CustomDrawTaskDependency += (sender, e) => { int predecessorId = Convert.ToInt32(e.PredecessorNode.GetValue("Id")); int successorId = Convert.ToInt32(e.SuccessorNode.GetValue("Id")); if(criticalPathIds.Contains(predecessorId) && criticalPathIds.Contains(successorId)) { e.Appearance.BackColor = DXSkinColors.FillColors.Danger; } };
拆分任務
拆分任務是被中斷的任務(在給定的時間),該任務在稍后的時間點恢復。 在下圖中,“Develop Software” 是一個3個小時的任務,一分為二,其中有2個小時的暫停。
使用custom draw事件時,您需要知道將拆分哪個任務及其延遲。有了這些信息,您就可以在數(shù)據(jù)源中編輯任務完成日期/持續(xù)時間。在此示例中,“Develop Software”被定義為數(shù)據(jù)源中的一個5小時任務。
ganttControl.CustomDrawTask += (sender, e) => { var splitInfo = e.Info.Node.GetValue("SplitInfo") as SplitInfo; if(splitInfo != null) { e.Appearance.BackColor = DXSkinColors.FillColors.Danger; e.Appearance.ProgressColor = DXSkinColors.FillColors.Danger; e.DrawShape(splitInfo.Start, splitInfo.Start + splitInfo.Duration); e.DrawRightText(); e.Handled = true; } };
一種更有效的方法是將任務持續(xù)時間和開始/結束日期存儲在數(shù)據(jù)源中,并在需要的地方插入暫停。 為了支持這種方法,甘特圖控件必須能夠重新計算所有任務并相應地動態(tài)更新其TreeList和Diagram面板。
自定義任務文本
下一個示例說明如何使用自定義文本字符串(“High Priority”或“Normal Priority”)替換任務的標題,這些自定義標題通過使用CustomTaskDisplayText事件繪制在任務的左側或右側。
HashSet<int> criticalPathIds = new HashSet<int> { 1, 2, 3, 6, 7, 8, 10, 11, 13 }; ganttControl.CustomTaskDisplayText += (sender, e) => { int taskId = Convert.ToInt32(e.Node.GetValue("Id")); if(criticalPathIds.Contains(taskId)) { e.RightText = "High priority"; } else { e.RightText = string.Empty; e.LeftText = "Normal priority"; } };
Striplines
Stripline是彩色的時間刻度列,突出顯示特定時間段(例如,周末)。 在下圖中,Stripline突出顯示了自定義的4小時間隔。
您可以通過CustomDrawTimescaleColumn事件重新繪制時標列來實現(xiàn)Striplines。
DateTime striplineStart = DateTime.Now.AddHours(5); DateTime striplineEnd = striplineStart.AddHours(4); Color striplineColor = Color.FromArgb(128, 255, 224, 166); ganttControl.CustomDrawTimescaleColumn += (sender, e) => { GanttTimescaleColumn column = e.Column; float stripLineStartPoint = (float) Math.Max(e.GetPosition(striplineStart), column.Bounds.Left); float stripLineEndPoint = (float) Math.Min(e.GetPosition(striplineEnd), column.Bounds.Right); e.DrawBackground(); RectangleF boundsToDraw = new RectangleF( stripLineStartPoint, column.Bounds.Y, stripLineEndPoint - stripLineStartPoint, column.Bounds.Height); if(boundsToDraw.Width > 0) e.Cache.FillRectangle(striplineColor, boundsToDraw); e.DrawHeader(); e.Handled = true; };
截止期限
在下圖中,“Deploy Beta”遵循固定的期限。
就像之前的代碼片段一樣,截止日期是通過CustomDrawTimescaleColumn事件繪制的,但是在這種情況下需要繪制一個細矩形,而不是用自定義顏色填充整個列。
DateTime deadLine = TaskStorage.GetFinishDateFromTask("Deploy Beta"); ganttControl.CustomDrawTimescaleColumn += (sender, e) => { GanttTimescaleColumn column = e.Column; if(column.StartDate <= deadLine && column.FinishDate >= deadLine) { e.DrawBackground(); float x = (float) e.GetPosition(deadLine); float width = 4; RectangleF deadLineRect = new RectangleF(x, column.Bounds.Y, width, column.Bounds.Height); e.Cache.FillRectangle(DXSkinColors.FillColors.Danger, deadLineRect); e.DrawHeader(); e.Handled = true; } };
DevExpress v19.2全新發(fā)布,歡迎下載最新版體驗哦~
DevExpress中文網(wǎng)官網(wǎng)QQ群:540330292 歡迎一起進群討論
掃描關注DevExpress中文網(wǎng)微信公眾號,及時獲取最新動態(tài)及最新資訊