diff --git a/GanttChart/GanttChart.bmp b/GanttChart/GanttChart.bmp
new file mode 100644
index 0000000..59b77fa
Binary files /dev/null and b/GanttChart/GanttChart.bmp differ
diff --git a/GanttChart/GanttChart.csproj b/GanttChart/GanttChart.csproj
new file mode 100644
index 0000000..7d3b358
--- /dev/null
+++ b/GanttChart/GanttChart.csproj
@@ -0,0 +1,105 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {DEA91CB9-1011-4EE7-B8E1-72428F731789}
+ Library
+ GanttChart
+ GanttChart
+ v4.7.2
+ 512
+ true
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Component
+
+
+ Component
+
+
+ Component
+
+
+ Component
+
+
+ Component
+
+
+
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+ True
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GanttChart/GanttChartBrushes.cs b/GanttChart/GanttChartBrushes.cs
new file mode 100644
index 0000000..ef2cceb
--- /dev/null
+++ b/GanttChart/GanttChartBrushes.cs
@@ -0,0 +1,197 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图笔刷
+ ///
+ class GanttChartBrushes: IDisposable
+ {
+ GanttChartView View { get; set; }
+ public GanttChartBrushes(GanttChartView view)
+ {
+ View = view;
+ this.GridBrush = new SolidBrush(view.GridColor);
+
+ this.ColumnDateTextBrush = new SolidBrush(view.ColumnDateTextColor);
+ this.ColumnHourTextBrush = new SolidBrush(view.ColumnHourTextColor);
+ this.HeaderBackBrush = new SolidBrush(view.HeaderBackColor);
+
+ this.BackBrush = new SolidBrush(view.BackColor);
+ this.ContentBackBrush = new SolidBrush(view.ContentBackColor);
+
+ this.CurrentTimeLineBrush = new SolidBrush(view.CurrentTimeLineColor);
+
+ this.ItemTextBrush = new SolidBrush(view.ItemTextColor);
+ this.ItemBackBrush = new SolidBrush(view.ItemBackColor);
+ this.ItemBorderBrush = new SolidBrush(view.ItemBorderColor);
+ this.ItemStartFlagBrush = new SolidBrush(view.ItemStartFlagColor);
+ this.ItemSubRangeBackBrush = new SolidBrush(view.ItemSubRangeBackColor);
+ this.ItemSelectionTextBrush = new SolidBrush(view.ItemSelectionTextColor);
+ this.ItemSelectionBackBrush = new SolidBrush(view.ItemSelectionBackColor);
+ this.ItemSelectionBorderBrush = new SolidBrush(view.ItemSelectionBorderColor);
+ this.ItemSelectionSubRangeBackBrush = new SolidBrush(view.ItemSelectionSubRangeBackColor);
+ this.ItemWarnningTextBrush = new SolidBrush(view.ItemWarnningTextColor);
+
+ this.RowHeaderTextBrush = new SolidBrush(view.RowHeaderTextColor);
+ this.RowSelectionHeaderTextBrush = new SolidBrush(view.RowSelectionHeaderTextColor);
+ this.RowSelectionBorderBrush = new SolidBrush(view.RowSelectionBorderColor);
+ this.RowSelectionHeaderBackBrush = new SolidBrush(view.RowSelectionHeaderBackColor);
+ this.RowSelectionContentBackBrush = new SolidBrush(view.RowSelectionContentBackColor);
+
+ this.TooltipTextBrush = new SolidBrush(view.TooltipTextColor);
+ this.TooltipBorderBrush = new SolidBrush(view.TooltipBorderColor);
+ this.TooltipBackBrush = new SolidBrush(view.TooltipBackColor);
+
+ this.TimeRangeSelecetionBackBrush = new SolidBrush(view.TimeRangeSelecetionBackColor);
+ this.SelectionRectangleBackBrush = new SolidBrush(view.SelectionRectangleBackColor);
+
+ this.GridPen = new Pen(this.GridBrush, 1);
+ this.CurrentTimeLinePen = new Pen(this.CurrentTimeLineBrush, 1);
+ this.ItemBorderPen = new Pen(this.ItemBorderBrush, 1);
+ this.ItemBackPen = new Pen(this.ItemBackBrush, 1);
+ this.ItemSelectionBorderPen = new Pen(this.ItemSelectionBorderBrush, 1);
+ this.RowSelectionBorderPen = new Pen(this.RowSelectionBorderBrush, 1);
+ this.TooltipBorderPen = new Pen(this.TooltipBorderBrush, 1);
+ this.ItemStartFlagPen = new Pen(this.ItemStartFlagBrush, 2);
+ this.ItemSubRangeBackPen = new Pen(this.ItemSubRangeBackBrush, 1);
+ this.ItemSelectionSubRangeBackPen = new Pen(this.ItemSelectionSubRangeBackBrush, 1);
+ }
+ public SolidBrush GridBrush { get; set; }
+
+ public SolidBrush ColumnDateTextBrush { get; set; }
+ public SolidBrush ColumnHourTextBrush { get; set; }
+ public SolidBrush HeaderBackBrush { get; set; }
+
+ public SolidBrush BackBrush { get; set; }
+ public SolidBrush ContentBackBrush { get; set; }
+
+ public SolidBrush CurrentTimeLineBrush { get; set; }
+
+ public SolidBrush ItemTextBrush { get; set; }
+ public SolidBrush ItemBackBrush { get; set; }
+ public SolidBrush ItemBorderBrush { get; set; }
+ public SolidBrush ItemStartFlagBrush { get; set; }
+ public SolidBrush ItemSubRangeBackBrush { get; set; }
+ public SolidBrush ItemSelectionTextBrush { get; set; }
+ public SolidBrush ItemSelectionBackBrush { get; set; }
+ public SolidBrush ItemSelectionBorderBrush { get; set; }
+ public SolidBrush ItemSelectionSubRangeBackBrush { get; set; }
+ public SolidBrush ItemWarnningTextBrush { get; set; }
+
+
+ public SolidBrush RowHeaderTextBrush { get; set; }
+ public SolidBrush RowSelectionHeaderTextBrush { get; set; }
+ public SolidBrush RowSelectionBorderBrush { get; set; }
+ public SolidBrush RowSelectionHeaderBackBrush { get; set; }
+ public SolidBrush RowSelectionContentBackBrush { get; set; }
+
+ public SolidBrush TooltipTextBrush { get; set; }
+ public SolidBrush TooltipBorderBrush { get; set; }
+ public SolidBrush TooltipBackBrush { get; set; }
+
+ public SolidBrush TimeRangeSelecetionBackBrush { get; set; }
+ public SolidBrush SelectionRectangleBackBrush { get; set; }
+
+ public Pen GridPen { get; }
+ public Pen CurrentTimeLinePen { get; }
+ public Pen ItemBorderPen { get; }
+ public Pen ItemBackPen { get; }
+ public Pen ItemSelectionBorderPen { get; }
+ public Pen RowSelectionBorderPen { get; }
+ public Pen TooltipBorderPen { get; }
+ public Pen ItemStartFlagPen { get; }
+ public Pen ItemSubRangeBackPen { get; }
+ public Pen ItemSelectionSubRangeBackPen { get; }
+
+ public void Refresh()
+ {
+ this.GridBrush.Color = View.GridColor;
+
+ this.ColumnDateTextBrush.Color = View.ColumnDateTextColor;
+ this.ColumnHourTextBrush.Color = View.ColumnHourTextColor;
+ this.HeaderBackBrush.Color = View.HeaderBackColor;
+
+ this.ContentBackBrush.Color = View.ContentBackColor;
+
+ this.CurrentTimeLineBrush.Color = View.CurrentTimeLineColor;
+
+ this.ItemTextBrush.Color = View.ItemTextColor;
+ this.ItemBackBrush.Color = View.ItemBackColor;
+ this.ItemBorderBrush.Color = View.ItemBorderColor;
+ this.ItemStartFlagBrush.Color = View.ItemStartFlagColor;
+ this.ItemSubRangeBackBrush.Color = View.ItemSubRangeBackColor;
+ this.ItemSelectionTextBrush.Color = View.ItemSelectionTextColor;
+ this.ItemSelectionBackBrush.Color = View.ItemSelectionBackColor;
+ this.ItemSelectionBorderBrush.Color = View.ItemSelectionBorderColor;
+ this.ItemSelectionSubRangeBackBrush.Color = View.ItemSelectionSubRangeBackColor;
+ this.ItemWarnningTextBrush.Color = View.ItemWarnningTextColor;
+
+ this.RowHeaderTextBrush.Color = View.RowHeaderTextColor;
+ this.RowSelectionHeaderTextBrush.Color = View.RowSelectionHeaderTextColor;
+ this.RowSelectionBorderBrush.Color = View.RowSelectionBorderColor;
+ this.RowSelectionHeaderBackBrush.Color = View.RowSelectionHeaderBackColor;
+ this.RowSelectionContentBackBrush.Color = View.RowSelectionContentBackColor;
+
+ this.TooltipTextBrush.Color = View.TooltipTextColor;
+ this.TooltipBorderBrush.Color = View.TooltipBorderColor;
+ this.TooltipBackBrush.Color = View.TooltipBackColor;
+
+ this.TimeRangeSelecetionBackBrush.Color = View.TimeRangeSelecetionBackColor;
+ this.SelectionRectangleBackBrush.Color = View.SelectionRectangleBackColor;
+ }
+
+ public void Dispose()
+ {
+ this.GridPen.Dispose();
+ this.CurrentTimeLinePen.Dispose();
+ this.ItemBorderPen.Dispose();
+ this.ItemBackPen.Dispose();
+ this.ItemSelectionBorderPen.Dispose();
+ this.RowSelectionBorderPen.Dispose();
+ this.TooltipBorderPen.Dispose();
+ this.ItemStartFlagPen.Dispose();
+ this.ItemSubRangeBackPen.Dispose();
+ this.ItemSelectionSubRangeBackPen.Dispose();
+
+ this.BackBrush.Dispose();
+ this.GridBrush.Dispose();
+
+ this.ColumnDateTextBrush.Dispose();
+ this.ColumnHourTextBrush.Dispose();
+ this.HeaderBackBrush.Dispose();
+
+ this.ContentBackBrush.Dispose();
+
+ this.CurrentTimeLineBrush.Dispose();
+
+ this.ItemTextBrush.Dispose();
+ this.ItemBackBrush.Dispose();
+ this.ItemBorderBrush.Dispose();
+ this.ItemStartFlagBrush.Dispose();
+ this.ItemSubRangeBackBrush.Dispose();
+ this.ItemSelectionTextBrush.Dispose();
+ this.ItemSelectionBackBrush.Dispose();
+ this.ItemSelectionBorderBrush.Dispose();
+ this.ItemSelectionSubRangeBackBrush.Dispose();
+ this.ItemWarnningTextBrush.Dispose();
+
+ this.RowHeaderTextBrush.Dispose();
+ this.RowSelectionHeaderTextBrush.Dispose();
+ this.RowSelectionBorderBrush.Dispose();
+ this.RowSelectionHeaderBackBrush.Dispose();
+ this.RowSelectionContentBackBrush.Dispose();
+
+ this.TooltipTextBrush.Dispose();
+ this.TooltipBorderBrush.Dispose();
+ this.TooltipBackBrush.Dispose();
+
+ this.TimeRangeSelecetionBackBrush.Dispose();
+ this.SelectionRectangleBackBrush.Dispose();
+ }
+ }
+}
diff --git a/GanttChart/GanttChartCollection.cs b/GanttChart/GanttChartCollection.cs
new file mode 100644
index 0000000..ea7c268
--- /dev/null
+++ b/GanttChart/GanttChartCollection.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图像集合
+ ///
+ ///
+ public class GanttChartCollection : ICollection
+ {
+ private List Items;
+ internal bool IsChanged { get; set; }
+ internal DateTime StartDate { get; set; }
+ public GanttChartCollection()
+ {
+ Items = new List();
+ }
+ public GanttChartCollection(ICollection items):this()
+ {
+ Items.AddRange(items);
+ IsChanged = true;
+ }
+ public int Count => Items.Count;
+
+ bool ICollection.IsReadOnly => false;
+
+ public void Add(T item)
+ {
+ Items.Add(item);
+ IsChanged = true;
+ }
+
+ public void Clear()
+ {
+ Items.Clear();
+ IsChanged = false;
+ }
+
+ public bool Contains(T item) => Items.Contains(item);
+
+ public void CopyTo(T[] array, int arrayIndex) => Items.CopyTo(array, arrayIndex);
+
+ public IEnumerator GetEnumerator() => Items.GetEnumerator();
+
+ public bool Remove(T item)
+ {
+ if (Items.Remove(item))
+ {
+ IsChanged = true;
+ return true;
+ }
+ return false;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return Items.GetEnumerator();
+ }
+ public T this[int index]
+ {
+ get
+ {
+ return Items[index];
+ }
+ }
+ }
+}
diff --git a/GanttChart/GanttChartItemClickEventArgs.cs b/GanttChart/GanttChartItemClickEventArgs.cs
new file mode 100644
index 0000000..a9f219b
--- /dev/null
+++ b/GanttChart/GanttChartItemClickEventArgs.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图项单击事件参数
+ ///
+ public class GanttChartItemClickEventArgs : EventArgs
+ {
+ ///
+ /// 项
+ ///
+ public GanttChartViewItem Item { get; private set; }
+ ///
+ /// 初始化
+ ///
+ ///
+ public GanttChartItemClickEventArgs(GanttChartViewItem item)
+ {
+ Item = item;
+ }
+ }
+}
diff --git a/GanttChart/GanttChartItemDoubleClickEventArgs.cs b/GanttChart/GanttChartItemDoubleClickEventArgs.cs
new file mode 100644
index 0000000..3400684
--- /dev/null
+++ b/GanttChart/GanttChartItemDoubleClickEventArgs.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图项双击事件参数
+ ///
+ public class GanttChartItemDoubleClickEventArgs : EventArgs
+ {
+ ///
+ /// 项
+ ///
+ public GanttChartViewItem Item { get; private set; }
+ ///
+ /// 初始化
+ ///
+ ///
+ public GanttChartItemDoubleClickEventArgs(GanttChartViewItem item)
+ {
+ Item = item;
+ }
+ }
+}
diff --git a/GanttChart/GanttChartPropertyChangeEventArgs.cs b/GanttChart/GanttChartPropertyChangeEventArgs.cs
new file mode 100644
index 0000000..9bed63d
--- /dev/null
+++ b/GanttChart/GanttChartPropertyChangeEventArgs.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图属性改变事件参数
+ ///
+ public class GanttChartPropertyChangeEventArgs : EventArgs
+ {
+ ///
+ /// 初始化
+ ///
+ ///
+ ///
+ public GanttChartPropertyChangeEventArgs(string name, object value)
+ {
+ PropertyName = name;
+ PropertyValue = value;
+ }
+ ///
+ /// 属性名
+ ///
+ public string PropertyName { get; set; }
+ ///
+ /// 属性值
+ ///
+ public object PropertyValue { get; set; }
+ }
+}
diff --git a/GanttChart/GanttChartRangeSelectedEventArgs.cs b/GanttChart/GanttChartRangeSelectedEventArgs.cs
new file mode 100644
index 0000000..9e1e715
--- /dev/null
+++ b/GanttChart/GanttChartRangeSelectedEventArgs.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图范围选择事件参数
+ ///
+ public class GanttChartRangeSelectedEventArgs : EventArgs
+ {
+ ///
+ /// 事件范围
+ ///
+ public TimeRange Range { get; private set; }
+ ///
+ /// 初始化
+ ///
+ ///
+ public GanttChartRangeSelectedEventArgs(TimeRange range)
+ {
+ Range = range;
+ }
+ ///
+ /// 初始化
+ ///
+ ///
+ ///
+ public GanttChartRangeSelectedEventArgs(DateTime startTime, DateTime endTime)
+ {
+ Range = new TimeRange { StartTime = startTime, EndTime = endTime };
+ }
+ }
+}
diff --git a/GanttChart/GanttChartRowSelectedEventArgs.cs b/GanttChart/GanttChartRowSelectedEventArgs.cs
new file mode 100644
index 0000000..628b441
--- /dev/null
+++ b/GanttChart/GanttChartRowSelectedEventArgs.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图行选中事件参数
+ ///
+ public class GanttChartRowSelectedEventArgs : EventArgs
+ {
+ ///
+ /// 行
+ ///
+ public GanttChartViewRow Row { get; private set; }
+ ///
+ /// 初始化
+ ///
+ ///
+ public GanttChartRowSelectedEventArgs(GanttChartViewRow row)
+ {
+ Row = row;
+ }
+ }
+}
diff --git a/GanttChart/GanttChartView.Events.cs b/GanttChart/GanttChartView.Events.cs
new file mode 100644
index 0000000..2cc5bf3
--- /dev/null
+++ b/GanttChart/GanttChartView.Events.cs
@@ -0,0 +1,410 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图控件
+ /// 该部分类主要处理事件
+ ///
+ public partial class GanttChartView
+ {
+ private bool _IsShiftPress = false;
+ private bool _IsCtrlPress = false;
+ private bool _IsAltPress = false;
+ private bool _IsMouseDown = false;
+ private bool _IsAjustSize = false;
+ private bool _IsDragItem = false;
+ private bool _IsShowTooltip = false;
+ private Point _DragStartLocation = Point.Empty;
+ private Point _DragEndLocation = Point.Empty;
+ private Point _ShowTooltipPoint = Point.Empty;
+ private Rectangle _SelectionRange = Rectangle.Empty;
+ private GanttChartViewItem _DragItem = null;
+ private GanttChartViewItem _ShowTooltipItem = null;
+ public event EventHandler PropertyChanged;
+ public event EventHandler ItemClick;
+ public event EventHandler ItemDoubleClick;
+ public event EventHandler RowSelected;
+ public event EventHandler RangeSelected;
+
+ ///
+ /// 初始化事件
+ ///
+ protected void InitEvent()
+ {
+ _VScrollBar.Scroll += new ScrollEventHandler(VScrollBar_Scroll);
+ _HScrollBar.Scroll += new ScrollEventHandler(HScrollBar_Scroll);
+ _ContentControl.Paint += OnContentControlPaint;
+ _ContentControl.MouseDown += OnMouseDown;
+ _ContentControl.MouseUp += OnMouseUp;
+ _ContentControl.MouseMove += OnMouseMove;
+ _ContentControl.MouseClick += OnMouseClick;
+ _ContentControl.MouseDoubleClick += OnMouseDoubleClick;
+ }
+ ///
+ /// 销毁事件
+ ///
+ protected void DisposeEvent()
+ {
+
+ }
+ ///
+ /// 键盘按下事件
+ ///
+ ///
+ protected override void OnKeyDown(KeyEventArgs e)
+ {
+ _IsShiftPress = e.Shift;
+ _IsCtrlPress = e.Control;
+ _IsAltPress = e.Alt;
+ base.OnKeyDown(e);
+ }
+ ///
+ /// 键盘弹起事件
+ ///
+ ///
+ protected override void OnKeyUp(KeyEventArgs e)
+ {
+ _IsShiftPress = e.Shift;
+ _IsCtrlPress = e.Control;
+ _IsAltPress = e.Alt;
+ base.OnKeyUp(e);
+ }
+ ///
+ /// 鼠标单击事件
+ ///
+ ///
+ ///
+ protected void OnMouseClick(object sender, MouseEventArgs e)
+ {
+ if (_DragStartLocation != Point.Empty && e.X != _DragStartLocation.X && _DragStartLocation.Y != e.Y)
+ {
+ return;
+ }
+ if (IsHoverRowHeader(e.Location) || IsHoverRow(e.Location))
+ {
+ _SelectionRow = GetRow(e.Location);
+ Invalidate();
+ RowSelected?.Invoke(this, new GanttChartRowSelectedEventArgs(_SelectionRow));
+ }
+ if (IsHoverItem(e.Location))
+ {
+ _SelectionItem = GetItem(e.Location);
+ Invalidate();
+ ItemClick?.Invoke(this, new GanttChartItemClickEventArgs(_SelectionItem));
+ }
+ }
+ ///
+ /// 鼠标双击事件
+ ///
+ ///
+ ///
+ protected void OnMouseDoubleClick(object sender, MouseEventArgs e)
+ {
+ if (IsHoverItem(e.Location))
+ {
+ _SelectionItem = GetItem(e.Location);
+ Invalidate();
+ if(ItemDoubleClick != null)
+ {
+ if (_IsShowTooltip)
+ {
+ _IsShowTooltip = false;
+ _ShowTooltipItem = null;
+ _ShowTooltipPoint = Point.Empty;
+ }
+ ItemDoubleClick(this, new GanttChartItemDoubleClickEventArgs(_SelectionItem));
+ }
+ }
+ }
+ ///
+ /// 鼠标滚动事件
+ ///
+ ///
+ protected override void OnMouseWheel(MouseEventArgs e)
+ {
+ if (_IsShowTooltip)
+ {
+ _IsShowTooltip = false;
+ _ShowTooltipItem = null;
+ _ShowTooltipPoint = Point.Empty;
+ }
+ //int i = e.Delta > 0 ? -1 : 1;
+ var scrollbar = _IsShiftPress ? _HScrollBar : (ScrollBar)_VScrollBar;
+ var h = scrollbar.Value - (int)(e.Delta * MouseWheelSensitivity);
+ if (h > scrollbar.Maximum)
+ {
+ h = scrollbar.Maximum;
+ }
+ if (h < scrollbar.Minimum)
+ {
+ h = scrollbar.Minimum;
+ }
+ scrollbar.Value = h;
+ Invalidate();
+ base.OnMouseWheel(e);
+ }
+ ///
+ /// 鼠标按下事件
+ ///
+ ///
+ ///
+ protected void OnMouseDown(object sender, MouseEventArgs e)
+ {
+ if (_SelectionRow != null || _SelectionItem != null || _DragItem != null)
+ {
+ _SelectionRow = null;
+ _SelectionItem = null;
+ _DragItem = null;
+ Invalidate();
+ }
+ _IsMouseDown = e.Button == MouseButtons.Left && true;
+ if (_IsMouseDown)
+ {
+ _SelectionRange = Rectangle.Empty;
+ _SelectionTimeRange = null;
+ _DragStartLocation = e.Location;
+ if (IsHoverDateSplitLine(e.Location) && !IsHoverItem(e.Location))
+ {
+ _IsAjustSize = true;
+ }
+ else if (IsHoverItem(e.Location))
+ {
+ _IsDragItem = true;
+ _DragItem = GetItem(e.Location);
+ }
+ }
+ }
+ ///
+ /// 控件创建事件
+ ///
+ protected override void OnCreateControl()
+ {
+ this.Brushes = new GanttChartBrushes(this);
+ _HScrollBar.Width = this.Width - VScrollWidth;
+ _VScrollBar.Height = this.Height - HScrollHeight;
+ AdjustScrollbar();
+ base.OnCreateControl();
+ }
+ ///
+ /// 控件大小变化事件
+ ///
+ ///
+ protected override void OnSizeChanged(EventArgs e)
+ {
+ _HScrollBar.Width = this.Width - VScrollWidth;
+ _VScrollBar.Height = this.Height - HScrollHeight;
+ AdjustScrollbar();
+ Invalidate();
+ base.OnSizeChanged(e);
+ }
+ ///
+ /// 控件绘制事件
+ ///
+ ///
+ ///
+ private void OnContentControlPaint(object sender, PaintEventArgs e)
+ {
+ int bottom = ColumnHeight + ItemHeight + RowSpacing * 2;
+ if (Rows != null && Rows.Any())
+ {
+ var last = Rows.Last();
+ bottom = last.Bottom;
+ }
+ DrawBack(e.Graphics, bottom);
+ e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
+ DrawHeader(e.Graphics, bottom);
+ DrawColumnHeader(e.Graphics);
+ DrawTimeLine(e.Graphics, bottom);
+
+ DrawSelectingRectangle(e.Graphics);
+
+ DrawSelectionRange(e.Graphics);
+
+ DrawRows(e.Graphics, bottom);
+
+ DrawItemTooltip(e.Graphics);
+ }
+ ///
+ /// 鼠标弹起事件
+ ///
+ ///
+ ///
+ protected void OnMouseUp(object sender, MouseEventArgs e)
+ {
+ if (_IsMouseDown)
+ {
+ if (_IsAjustSize)
+ {
+ _IsAjustSize = false;
+ var w = e.X - _DragStartLocation.X + DateWidth;
+ if (w < MinDateWidth)
+ {
+ DateWidth = MinDateWidth;
+ }
+ else
+ {
+ DateWidth = (w / 48 + (w % 48 == 0 ? 0 : 1)) * 48;
+ }
+ if(Rows != null)
+ {
+ Rows.IsChanged = true;
+ }
+ AdjustScrollbar();
+ Invalidate();
+ }
+ else if (_IsDragItem)
+ {
+ _IsDragItem = false;
+ //TODO:触发Drag事件
+ Invalidate();
+ }
+ else if(!_DragStartLocation.IsEmpty && e.X != _DragStartLocation.X && e.Y != _DragStartLocation.Y && _DragStartLocation.X > RowHeaderWidth && _DragStartLocation.Y > ColumnHeight)
+ {
+ _DragEndLocation = e.Location;
+ var row = GetRow(_DragStartLocation);
+ if (row != null)
+ {
+ var width = Math.Abs(_DragEndLocation.X - _DragStartLocation.X);
+ if (_DragEndLocation.X < RowHeaderWidth)
+ {
+ width -= RowHeaderWidth - _DragEndLocation.X;
+ }
+ else if (_DragEndLocation.X > ((int)(EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value)
+ {
+ width = ((int)(EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value - _DragStartLocation.X;
+ }
+ var start = new Point(Math.Min(_DragStartLocation.X, Math.Max(_DragEndLocation.X, RowHeaderWidth)), row.Top + 1);
+ _SelectionRange = new Rectangle(start, new Size(width, row.Bottom - row.Top - 2));
+
+ Invalidate();
+ var mw = DateWidth / 24f / 60f;
+ var ts = StartDate.AddMinutes((int)((_DragStartLocation.X - RowHeaderWidth + _HScrollBar.Value) / mw));
+ var te = StartDate.AddMinutes((int)((_DragEndLocation.X - RowHeaderWidth + _HScrollBar.Value) / mw));
+ if (te < ts)
+ {
+ var tt = te;
+ te = ts;
+ ts = tt;
+ }
+ _SelectionTimeRange = new TimeRange { StartTime = ts, EndTime = te };
+ RangeSelected?.Invoke(this, new GanttChartRangeSelectedEventArgs(ts, te));
+ }
+ }
+ }
+ _IsMouseDown = false;
+ _DragStartLocation = Point.Empty;
+ _DragEndLocation = Point.Empty;
+ }
+ ///
+ /// 鼠标移动事件
+ ///
+ ///
+ ///
+ protected void OnMouseMove(object sender, MouseEventArgs e)
+ {
+ if (_IsMouseDown)
+ {
+ if (_IsShowTooltip)
+ {
+ _IsShowTooltip = false;
+ _ShowTooltipItem = null;
+ _ShowTooltipPoint = Point.Empty;
+
+ Invalidate();
+ }
+ if (_IsDragItem)
+ {
+
+ }
+ else if (_DragStartLocation.X > RowHeaderWidth && _DragStartLocation.Y > ColumnHeight)
+ {
+ //TODO: 画选择框
+ _DragEndLocation = e.Location;
+ Invalidate();
+ }
+ return;
+ }
+ else if (IsHoverDateSplitLine(e.Location) && !IsHoverItem(e.Location))
+ {
+ Cursor = Cursors.VSplit;
+ }
+ //else if (IsHoverRowHeader(e))
+ //{
+ // Cursor = DefaultCursor;
+ //}
+ else if (IsHoverItem(e.Location))
+ {
+ Cursor = Cursors.Hand;
+ //TODO:显示Tooltip
+ if (!_IsShowTooltip || GetItem(e.Location) != _ShowTooltipItem)
+ {
+ _IsShowTooltip = true;
+ _ShowTooltipItem = GetItem(e.Location);
+ _ShowTooltipPoint = ComputeTooltipLocation(e.Location);
+
+ Invalidate();
+ return;
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ Cursor = DefaultCursor;
+ }
+ if (_IsShowTooltip)
+ {
+ _IsShowTooltip = false;
+ _ShowTooltipItem = null;
+ _ShowTooltipPoint = Point.Empty;
+
+ Invalidate();
+ }
+ }
+
+
+ ///
+ /// 横向滚动事件
+ ///
+ ///
+ ///
+ private void HScrollBar_Scroll(object sender, ScrollEventArgs e)
+ {
+ Invalidate();
+ }
+ ///
+ /// 纵向滚动事件
+ ///
+ ///
+ ///
+ private void VScrollBar_Scroll(object sender, ScrollEventArgs e)
+ {
+ Invalidate();
+ }
+ ///
+ /// 属性改变事件
+ ///
+ ///
+ ///
+ private void OnPropertyChanged(string name, object value)
+ {
+ this.Brushes?.Refresh();
+ var args = new GanttChartPropertyChangeEventArgs(name, value);
+ PropertyChanged?.Invoke(this, args);
+ if(name == nameof(BlockType))
+ {
+ Rows.IsChanged = true;
+ }
+ AdjustScrollbar();
+ Invalidate();
+ }
+ }
+}
diff --git a/GanttChart/GanttChartView.Logic.cs b/GanttChart/GanttChartView.Logic.cs
new file mode 100644
index 0000000..edea944
--- /dev/null
+++ b/GanttChart/GanttChartView.Logic.cs
@@ -0,0 +1,217 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图控件
+ /// 该部分类处理甘特图逻辑
+ ///
+ public partial class GanttChartView
+ {
+ ///
+ /// 鼠标是否经过日分割线
+ ///
+ ///
+ ///
+ private bool IsHoverDateSplitLine(Point e)
+ {
+ var t = (e.X + _HScrollBar.Value - RowHeaderWidth + this.DateWidth) % this.DateWidth;
+ return e.X > this.RowHeaderWidth + 3 && e.X < ((EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value && (this.DateWidth - 2 <= t || t <= 1);
+ }
+ ///
+ /// 鼠标是否经过行标题
+ ///
+ ///
+ ///
+ private bool IsHoverRowHeader(Point e)
+ {
+ return e.X <= this.RowHeaderWidth && e.Y > this.ColumnHeight;
+ }
+ ///
+ /// 鼠标是否经过行
+ ///
+ ///
+ ///
+ private bool IsHoverRow(Point e)
+ {
+ var y = e.Y + _VScrollBar.Value;
+ return e.X < ((EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value && e.Y > this.ColumnHeight && Rows != null ? Rows.Any(r=>r.Top <= y && r.Bottom >= y) : false;
+ }
+ ///
+ /// 鼠标是否经过项
+ ///
+ ///
+ ///
+ private bool IsHoverItem(Point e)
+ {
+ if(e.X > this.RowHeaderWidth && e.Y > this.ColumnHeight && Rows != null)
+ {
+ var row = GetRow(e);
+ if (row != null && row.Items != null && row.Items.Any())
+ {
+ var x = e.X + _HScrollBar.Value;
+ var y = e.Y + _VScrollBar.Value;
+ return row.Items.Any(r=>r.Left<=x && x <= r.Left + Math.Max(r.Width, r.TextWidth) && r.Top <= y && y <= r.Top + ItemHeight);
+ }
+ }
+ return false;
+ }
+ ///
+ /// 获取项
+ ///
+ ///
+ ///
+ private GanttChartViewItem GetItem(Point e)
+ {
+ if (e.X > this.RowHeaderWidth && e.X < ((EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value && e.Y > this.ColumnHeight && Rows != null)
+ {
+ var row = GetRow(e);
+ if (row != null && row.Items != null && row.Items.Any())
+ {
+ var x = e.X + _HScrollBar.Value;
+ var y = e.Y + _VScrollBar.Value;
+ return row.Items.OrderBy(r=>r.Left).LastOrDefault(r => r.Left <= x && x <= r.Left + Math.Max(r.Width, r.TextWidth) && r.Top <= y && y <= r.Top + ItemHeight);
+ }
+ }
+ return null;
+ }
+ ///
+ /// 获取行
+ ///
+ ///
+ ///
+ private GanttChartViewRow GetRow(Point e)
+ {
+ if (e.X < ((EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value && e.Y > this.ColumnHeight && e.Y + _VScrollBar.Value < (Rows == null || !Rows.Any() ? 0 : Rows.Max(r=>r.Bottom)) && Rows != null)
+ {
+ var y = e.Y + _VScrollBar.Value;
+ return Rows.FirstOrDefault(r => r.Top <= y && r.Bottom >= y);
+ }
+ return null;
+ }
+ ///
+ /// 计算所有行和项的大小
+ ///
+ private void ComputeRowsAndItemsSize()
+ {
+ var minuteWidth = DateWidth / 24f / 60f;
+ var currentRowY = ColumnHeight;
+ foreach (var row in Rows)
+ {
+ row.Top = currentRowY;
+ var currentItemY = currentRowY + RowSpacing;
+ row.Bottom = currentRowY;
+ if(row.Items != null)
+ {
+ var beforeTop = row.Top + RowSpacing;
+ var beforeRight = 0;
+ var items = row.Items.OrderBy(r => r.StartTime).ToList();
+ for ( int i = 0; i < items.Count; i++)
+ {
+ var item = items[i];
+ if (item.EndTime >= StartTime && item.StartTime <= EndTime && item.EndTime >= item.StartTime)
+ {
+ item.Left = (int)((item.StartTime - StartTime).TotalMinutes * minuteWidth) + RowHeaderWidth;
+ item.Width = (int)((item.EndTime - item.StartTime).TotalMinutes * minuteWidth);
+ item.TextWidth = TextRenderer.MeasureText(item.Title, ItemTextFont, System.Drawing.Size.Empty).Width;
+ if (item.Left < beforeRight || BlockType == GanttChartViewItemBlockType.Block && i > 0)
+ {
+ var its = items.Take(i).GroupBy(r=>r.Top).Select(r=>r.OrderByDescending(p => p.Left + p.TextWidth).First());
+ if(BlockType == GanttChartViewItemBlockType.Return && its.Any(r=>r.Left + r.TextWidth < item.Left))
+ {
+ var it = its.First(r => r.Left + r.TextWidth < item.Left);
+ item.Top = it.Top;
+ beforeTop = it.Top;
+ }
+ else
+ {
+ if(BlockType == GanttChartViewItemBlockType.Return && its.Any())
+ {
+ beforeTop = its.Max(r => r.Top);
+ }
+ item.Top = beforeTop + ItemHeight + ItemSpacing;
+ beforeTop += ItemHeight + ItemSpacing;
+ }
+ }
+ else
+ {
+ if (i > 0)
+ {
+ if (BlockType == GanttChartViewItemBlockType.Return && beforeTop != row.Top + RowSpacing)
+ {
+ beforeTop = row.Top + RowSpacing;
+ }
+ }
+ item.Top = beforeTop;
+ }
+ if (BlockType == GanttChartViewItemBlockType.Compact)
+ {
+ beforeRight = item.Left + item.Width;
+ }
+ else
+ {
+ beforeRight = item.Left + Math.Max(item.TextWidth, item.Width);
+ }
+ if (item.Ranges != null && item.Ranges.Any())
+ {
+ var subs = item.Ranges.OrderBy(r => r.StartTime);
+ foreach (var sub in subs)
+ {
+ sub.Left = item.Left + (int)((sub.StartTime - item.StartTime).TotalMinutes * minuteWidth);
+ sub.Width = (int)((sub.EndTime - sub.StartTime).TotalMinutes * minuteWidth);
+ }
+ }
+ }
+ else
+ {
+ //row.Items.Remove(item);
+ //i--;
+ }
+ }
+ }
+ if (row.Items == null || !row.Items.Any(r=>r.Left > 0))
+ {
+ row.Bottom = row.Top + ItemHeight + RowSpacing * 2;
+ }
+ else
+ {
+ row.Bottom = Math.Max(row.Items.Max(r => r.Top), ColumnHeight + RowSpacing) + ItemHeight + RowSpacing;
+ }
+ currentRowY = row.Bottom;
+ }
+ }
+ ///
+ /// 计算提示框的位置
+ ///
+ ///
+ ///
+ private Point ComputeTooltipLocation(Point e)
+ {
+ var size = TooltipOuterSize;
+ var x = e.X;
+ if (e.X + size.Width > _ContentControl.Width)
+ {
+ var t = e.X - size.Width;
+ if (t < 0 && 0 - t < (e.X + size.Width) - _ContentControl.Width || t >= 0)
+ {
+ x = t;
+ }
+ }
+ var y = _ShowTooltipItem.Top - _VScrollBar.Value + ItemHeight + ItemSpacing;
+ if(y + size.Height > _ContentControl.Height)
+ {
+ var t = _ShowTooltipItem.Top - _VScrollBar.Value - ItemSpacing - size.Height;
+ if (t < 0 && 0 - t < (y + size.Height) - _ContentControl.Height || t >= 0)
+ {
+ y = t;
+ }
+ }
+ return new Point(x, y);
+ }
+ }
+}
diff --git a/GanttChart/GanttChartView.Properties.cs b/GanttChart/GanttChartView.Properties.cs
new file mode 100644
index 0000000..ebc8ac3
--- /dev/null
+++ b/GanttChart/GanttChartView.Properties.cs
@@ -0,0 +1,756 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图控件
+ /// 该部分类主要是甘特图的属性
+ ///
+ public partial class GanttChartView
+ {
+ #region Fonts
+ private Font _ColumnDateTextFont = DefaultFont;
+
+ ///
+ /// 日期字体
+ ///
+ public Font ColumnDateTextFont
+ {
+ get { return _ColumnDateTextFont; }
+ set { _ColumnDateTextFont = value; OnPropertyChanged(nameof(ColumnDateTextFont), value); }
+ }
+
+ private Font _ColumnHourTextFont = DefaultFont;
+
+ ///
+ /// 时间字体
+ ///
+ public Font ColumnHourTextFont
+ {
+ get { return _ColumnHourTextFont; }
+ set { _ColumnHourTextFont = value; OnPropertyChanged(nameof(ColumnHourTextFont), value); }
+ }
+
+ private Font _RowHeaderTextFont = DefaultFont;
+
+ ///
+ /// 行标题字体
+ ///
+ public Font RowHeaderTextFont
+ {
+ get { return _RowHeaderTextFont; }
+ set { _RowHeaderTextFont = value; OnPropertyChanged(nameof(RowHeaderTextFont), value); }
+ }
+
+ private Font _ItemTextFont = DefaultFont;
+
+ ///
+ /// 项字体
+ ///
+ public Font ItemTextFont
+ {
+ get { return _ItemTextFont; }
+ set { _ItemTextFont = value; OnPropertyChanged(nameof(ItemTextFont), value); }
+ }
+
+ private Font _TooltipTextFont = DefaultFont;
+
+ ///
+ /// 提示文字字体
+ ///
+ public Font TooltipTextFont
+ {
+ get { return _TooltipTextFont; }
+ set { _TooltipTextFont = value; OnPropertyChanged(nameof(TooltipTextFont), value); }
+ }
+ #endregion
+ #region Colors
+ private Color _GridColor = Color.FromArgb(210, 210, 210);
+
+ ///
+ /// 网格颜色
+ ///
+ public Color GridColor
+ {
+ get { return _GridColor; }
+ set { _GridColor = value; OnPropertyChanged(nameof(GridColor), value); }
+ }
+
+ private Color _ColumnDateTextColor = Color.FromArgb(102, 102, 102);
+
+ ///
+ /// 日期文字颜色
+ ///
+ public Color ColumnDateTextColor
+ {
+ get { return _ColumnDateTextColor; }
+ set { _ColumnDateTextColor = value; OnPropertyChanged(nameof(ColumnDateTextColor), value); }
+ }
+
+ private Color _ColumnHourTextColor = Color.FromArgb(102, 102, 102);
+
+ ///
+ /// 小时文字颜色
+ ///
+ public Color ColumnHourTextColor
+ {
+ get { return _ColumnHourTextColor; }
+ set { _ColumnHourTextColor = value; OnPropertyChanged(nameof(ColumnHourTextColor), value); }
+ }
+
+ private Color _HeaderBackColor = Color.FromArgb(247, 247, 247);
+
+ ///
+ /// 标题背景颜色
+ ///
+ public Color HeaderBackColor
+ {
+ get { return _HeaderBackColor; }
+ set { _HeaderBackColor = value; OnPropertyChanged(nameof(HeaderBackColor), value); }
+ }
+
+ private Color _ContentBackColor = Color.White;
+
+ ///
+ /// 内容背景颜色
+ ///
+ public Color ContentBackColor
+ {
+ get { return _ContentBackColor; }
+ set { _ContentBackColor = value; OnPropertyChanged(nameof(ContentBackColor), value); }
+ }
+
+ private Color _CurrentTimeLineColor = Color.Red;
+
+ ///
+ /// 当前时间线颜色
+ ///
+ public Color CurrentTimeLineColor
+ {
+ get { return _CurrentTimeLineColor; }
+ set { _CurrentTimeLineColor = value; OnPropertyChanged(nameof(CurrentTimeLineColor), value); }
+ }
+
+ private Color _ItemTextColor = Color.FromArgb(51, 51, 51);
+
+ ///
+ /// 项文字颜色
+ ///
+ public Color ItemTextColor
+ {
+ get { return _ItemTextColor; }
+ set { _ItemTextColor = value; OnPropertyChanged(nameof(ItemTextColor), value); }
+ }
+
+ private Color _ItemBackColor = Color.FromArgb(190, 190, 190);
+
+ ///
+ /// 项背景颜色
+ ///
+ public Color ItemBackColor
+ {
+ get { return _ItemBackColor; }
+ set { _ItemBackColor = value; OnPropertyChanged(nameof(ItemBackColor), value); }
+ }
+
+ private Color _ItemBorderColor = Color.FromArgb(18, 170, 11);
+
+ ///
+ /// 项边框颜色
+ ///
+ public Color ItemBorderColor
+ {
+ get { return _ItemBorderColor; }
+ set { _ItemBorderColor = value; OnPropertyChanged(nameof(ItemBorderColor), value); }
+ }
+
+ private Color _ItemStartFlagColor = Color.Red;
+
+ ///
+ /// 项首标志颜色
+ ///
+ public Color ItemStartFlagColor
+ {
+ get { return _ItemStartFlagColor; }
+ set { _ItemStartFlagColor = value; OnPropertyChanged(nameof(ItemStartFlagColor), value); }
+ }
+
+ private Color _ItemSubRangeBackColor = Color.FromArgb(153, 201, 255);
+
+ ///
+ /// 项时间范围背景颜色
+ ///
+ public Color ItemSubRangeBackColor
+ {
+ get { return _ItemSubRangeBackColor; }
+ set { _ItemSubRangeBackColor = value; OnPropertyChanged(nameof(ItemSubRangeBackColor), value); }
+ }
+
+ private Color _ItemSelectionTextColor = Color.FromArgb(18, 170, 11);
+
+ ///
+ /// 选中项文字颜色
+ ///
+ public Color ItemSelectionTextColor
+ {
+ get { return _ItemSelectionTextColor; }
+ set { _ItemSelectionTextColor = value; OnPropertyChanged(nameof(ItemSelectionTextColor), value); }
+ }
+
+ private Color _ItemSelectionBackColor = Color.FromArgb(229, 249, 229);
+
+ ///
+ /// 选中项背景颜色
+ ///
+ public Color ItemSelectionBackColor
+ {
+ get { return _ItemSelectionBackColor; }
+ set { _ItemSelectionBackColor = value; OnPropertyChanged(nameof(ItemSelectionBackColor), value); }
+ }
+
+ private Color _ItemSelectionBorderColor = Color.FromArgb(18, 170, 11);
+
+ ///
+ /// 选中项边框颜色
+ ///
+ public Color ItemSelectionBorderColor
+ {
+ get { return _ItemSelectionBorderColor; }
+ set { _ItemSelectionBorderColor = value; OnPropertyChanged(nameof(ItemSelectionBorderColor), value); }
+ }
+
+ private Color _ItemSelectionSubRangeBackColor = Color.FromArgb(153, 201, 255);
+
+ ///
+ /// 选中项时间范围背景颜色
+ ///
+ public Color ItemSelectionSubRangeBackColor
+ {
+ get { return _ItemSelectionSubRangeBackColor; }
+ set { _ItemSelectionSubRangeBackColor = value; OnPropertyChanged(nameof(ItemSelectionSubRangeBackColor), value); }
+ }
+
+ private Color _RowHeaderTextColor = Color.FromArgb(102, 102, 102);
+
+ ///
+ /// 行标题文字颜色
+ ///
+ public Color RowHeaderTextColor
+ {
+ get { return _RowHeaderTextColor; }
+ set { _RowHeaderTextColor = value; OnPropertyChanged(nameof(RowHeaderTextColor), value); }
+ }
+
+ private Color _RowSelectionHeaderTextColor = Color.FromArgb(102, 102, 102);
+
+ ///
+ /// 选中行标题文字颜色
+ ///
+ public Color RowSelectionHeaderTextColor
+ {
+ get { return _RowSelectionHeaderTextColor; }
+ set { _RowSelectionHeaderTextColor = value; OnPropertyChanged(nameof(RowSelectionHeaderTextColor), value); }
+ }
+
+ private Color _RowSelectionBorderColor = Color.FromArgb(247, 247, 247);
+
+ ///
+ /// 选中行边框颜色
+ ///
+ public Color RowSelectionBorderColor
+ {
+ get { return _RowSelectionBorderColor; }
+ set { _RowSelectionBorderColor = value; OnPropertyChanged(nameof(RowSelectionBorderColor), value); }
+ }
+
+ private Color _RowSelectionHeaderBackColor = Color.FromArgb(247, 247, 247);
+
+ ///
+ /// 选中行标题背景颜色
+ ///
+ public Color RowSelectionHeaderBackColor
+ {
+ get { return _RowSelectionHeaderBackColor; }
+ set { _RowSelectionHeaderBackColor = value; OnPropertyChanged(nameof(RowSelectionHeaderBackColor), value); }
+ }
+
+ private Color _RowSelectionContentBackColor = Color.FromArgb(247, 247, 247);
+
+ ///
+ /// 选中行内容背景颜色
+ ///
+ public Color RowSelectionContentBackColor
+ {
+ get { return _RowSelectionContentBackColor; }
+ set { _RowSelectionContentBackColor = value; OnPropertyChanged(nameof(RowSelectionContentBackColor), value); }
+ }
+
+ private Color _TooltipTextColor = Color.FromArgb(237, 237, 237);
+
+ ///
+ /// 提示文字颜色
+ ///
+ public Color TooltipTextColor
+ {
+ get { return _TooltipTextColor; }
+ set { _TooltipTextColor = value; OnPropertyChanged(nameof(TooltipTextColor), value); }
+ }
+
+ private Color _TooltipBorderColor = Color.FromArgb(102, 0, 0, 0);
+
+ ///
+ /// 提示边框颜色
+ ///
+ public Color TooltipBorderColor
+ {
+ get { return _TooltipBorderColor; }
+ set { _TooltipBorderColor = value; OnPropertyChanged(nameof(TooltipBorderColor), value); }
+ }
+
+ private Color _TooltipBackColor = Color.FromArgb(102, 0, 0, 0);
+
+ ///
+ /// 提示背景颜色
+ ///
+ public Color TooltipBackColor
+ {
+ get { return _TooltipBackColor; }
+ set { _TooltipBackColor = value; OnPropertyChanged(nameof(TooltipBackColor), value); }
+ }
+
+ private Color _TimeRangeSelecetionBackColor = Color.FromArgb(153, 201, 255);
+
+ ///
+ /// 选中时间范围背景颜色
+ ///
+ public Color TimeRangeSelecetionBackColor
+ {
+ get { return _TimeRangeSelecetionBackColor; }
+ set { _TimeRangeSelecetionBackColor = value; OnPropertyChanged(nameof(TimeRangeSelecetionBackColor), value); }
+ }
+
+ private Color _SelectionRectangleBackColor = Color.FromArgb(80, 210, 210, 210);
+
+ ///
+ /// 选择框背景颜色
+ ///
+ public Color SelectionRectangleBackColor
+ {
+ get { return _SelectionRectangleBackColor; }
+ set { _SelectionRectangleBackColor = value; OnPropertyChanged(nameof(SelectionRectangleBackColor), value); }
+ }
+
+ private Color _ItemWarnningTextColor = Color.Red;
+
+ ///
+ /// 项警告文字颜色
+ ///
+ public Color ItemWarnningTextColor
+ {
+ get { return _ItemWarnningTextColor; }
+ set { _ItemWarnningTextColor = value; OnPropertyChanged(nameof(ItemWarnningTextColor), value); }
+ }
+ #endregion
+ #region Mouse
+ private float _MouseWheelSensitivity = 0.5f;
+
+ ///
+ /// 鼠标滚轮灵敏度
+ ///
+ [DefaultValue(0.5f)]
+ public float MouseWheelSensitivity
+ {
+ get { return _MouseWheelSensitivity; }
+ set { _MouseWheelSensitivity = value; OnPropertyChanged(nameof(MouseWheelSensitivity), value); }
+ }
+ #endregion
+ #region Size
+ private int _ItemHeight = 30;
+
+ ///
+ /// 项高度
+ ///
+ [DefaultValue(30)]
+ public int ItemHeight
+ {
+ get { return _ItemHeight; }
+ set { _ItemHeight = value; OnPropertyChanged(nameof(ItemHeight), value); }
+ }
+
+ private int _RowHeaderWidth = 150;
+
+ ///
+ /// 行标题宽度
+ ///
+ [DefaultValue(150)]
+ public int RowHeaderWidth
+ {
+ get { return _RowHeaderWidth; }
+ set { _RowHeaderWidth = value; OnPropertyChanged(nameof(RowHeaderWidth), value); }
+ }
+
+ private int _RowHeight = 100;
+
+ ///
+ /// 行高
+ ///
+ [DefaultValue(100)]
+ public int RowHeight
+ {
+ get { return _RowHeight; }
+ set { _RowHeight = value; OnPropertyChanged(nameof(RowHeight), value); }
+ }
+
+ private int _ColumnDateHeight = 30;
+
+ ///
+ /// 日期高度
+ ///
+ [DefaultValue(30)]
+ public int ColumnDateHeight
+ {
+ get { return _ColumnDateHeight; }
+ set { _ColumnDateHeight = value; OnPropertyChanged(nameof(ColumnDateHeight), value); }
+ }
+
+ private int _ColumnHourHeight = 30;
+
+ ///
+ /// 小时高度
+ ///
+ [DefaultValue(30)]
+ public int ColumnHourHeight
+ {
+ get { return _ColumnHourHeight; }
+ set { _ColumnHourHeight = value; OnPropertyChanged(nameof(ColumnHourHeight), value); }
+ }
+
+ private int _DateWidth = MinDateWidth;
+
+ ///
+ /// 日期宽度
+ ///
+ [DefaultValue(MinDateWidth)]
+ public int DateWidth
+ {
+ get { return _DateWidth; }
+ set { _DateWidth = value; OnPropertyChanged(nameof(DateWidth), value); }
+ }
+
+ private int _HScrollHeight = 15;
+
+ ///
+ /// 横向滚动条高度
+ ///
+ [DefaultValue(15)]
+ public int HScrollHeight
+ {
+ get { return _HScrollHeight; }
+ set { _HScrollHeight = value; OnPropertyChanged(nameof(HScrollHeight), value); }
+ }
+
+ private int _VScrollWidth = 15;
+
+ ///
+ /// 纵向滚动条宽度
+ ///
+ [DefaultValue(15)]
+ public int VScrollWidth
+ {
+ get { return _VScrollWidth; }
+ set { _VScrollWidth = value; OnPropertyChanged(nameof(VScrollWidth), value); }
+ }
+
+ private int _ItemSpacing = 2;
+
+ ///
+ /// 项的行间距
+ ///
+ [DefaultValue(2)]
+ public int ItemSpacing
+ {
+ get { return _ItemSpacing; }
+ set { _ItemSpacing = value; OnPropertyChanged(nameof(ItemSpacing), value); }
+ }
+
+ private int _RowSpacing = 5;
+
+ ///
+ /// 行间距
+ ///
+ [DefaultValue(5)]
+ public int RowSpacing
+ {
+ get { return _RowSpacing; }
+ set { _RowSpacing = value; OnPropertyChanged(nameof(RowSpacing), value); }
+ }
+ #endregion
+ #region Control
+ private bool _IsFixedRowHeight = false;
+
+ ///
+ /// 是否固定行高
+ ///
+ [DefaultValue(false)]
+ public bool IsFixedRowHeight
+ {
+ get { return _IsFixedRowHeight; }
+ set { _IsFixedRowHeight = value; OnPropertyChanged(nameof(IsFixedRowHeight), value); }
+ }
+
+ private bool _EnableEdit = false;
+
+ ///
+ /// 启用编辑
+ ///
+ [DefaultValue(false)]
+ public bool EnableEdit
+ {
+ get { return _EnableEdit; }
+ set { _EnableEdit = value; OnPropertyChanged(nameof(EnableEdit), value); }
+ }
+
+ private bool _AllowItemNotWrap = true;
+
+ ///
+ /// 允许项文字换行
+ ///
+ [DefaultValue(true)]
+ public bool AllowItemNotWrap
+ {
+ get { return _AllowItemNotWrap; }
+ set { _AllowItemNotWrap = value; OnPropertyChanged(nameof(AllowItemNotWrap), value); }
+ }
+
+ private bool _IsShowItemBorder = false;
+
+ ///
+ /// 是否显示项边框
+ ///
+ [DefaultValue(false)]
+ public bool IsShowItemBorder
+ {
+ get { return _IsShowItemBorder; }
+ set { _IsShowItemBorder = value; OnPropertyChanged(nameof(IsShowItemBorder), value); }
+ }
+
+ private bool _AllowHeaderNotWrap = true;
+
+ ///
+ /// 允许行标题文字换行
+ ///
+ [DefaultValue(true)]
+ public bool AllowHeaderNotWrap
+ {
+ get { return _AllowHeaderNotWrap; }
+ set { _AllowHeaderNotWrap = value; OnPropertyChanged(nameof(AllowHeaderNotWrap), value); }
+ }
+
+ private GanttChartViewItemBlockType _BlockType = GanttChartViewItemBlockType.TextOverBlock;
+
+ ///
+ /// 项换行模式
+ ///
+ public GanttChartViewItemBlockType BlockType
+ {
+ get { return _BlockType; }
+ set { _BlockType = value; OnPropertyChanged(nameof(BlockType), value); }
+ }
+
+ private bool _IsShowSelectionBorder = false;
+
+ ///
+ /// 显示行选中高亮边框
+ ///
+ [DefaultValue(false)]
+ public bool IsShowSelectionBorder
+ {
+ get { return _IsShowSelectionBorder; }
+ set { _IsShowSelectionBorder = value; OnPropertyChanged(nameof(IsShowSelectionBorder), value); }
+ }
+
+ private bool _AllowSelectRange = false;
+
+ ///
+ /// 允许选中时间范围
+ ///
+ [DefaultValue(false)]
+ public bool AllowSelectRange
+ {
+ get { return _AllowSelectRange; }
+ set { _AllowSelectRange = value; OnPropertyChanged(nameof(AllowSelectRange), value); }
+ }
+
+ private Func _SelectionItemSameComparator = null;
+
+ ///
+ /// 选择项的同类项比较器
+ ///
+ public Func SelectionItemSameComparator
+ {
+ get { return _SelectionItemSameComparator; }
+ set { _SelectionItemSameComparator = value; }
+ }
+ #endregion
+ #region DataSource
+ private DateTime _StartDate = DateTime.Today;
+
+ ///
+ /// 开始日期
+ ///
+ public DateTime StartDate
+ {
+ get { return _StartDate; }
+ set { _StartDate = value; OnPropertyChanged(nameof(StartDate), value); }
+ }
+
+ private DateTime _EndDate = DateTime.Today.AddDays(1);
+
+ ///
+ /// 结束日期
+ ///
+ public DateTime EndDate
+ {
+ get { return _EndDate; }
+ set { _EndDate = value; OnPropertyChanged(nameof(EndDate), value); }
+ }
+
+ private GanttChartCollection _Rows = new GanttChartCollection();
+
+ ///
+ /// 行集合
+ ///
+ public GanttChartCollection Rows
+ {
+ get { return _Rows; }
+ set { _Rows = value; OnPropertyChanged(nameof(Rows), value); }
+ }
+
+ private GanttChartViewRow _SelectionRow = null;
+
+ ///
+ /// 选中的行
+ ///
+ public GanttChartViewRow SelectionRow
+ {
+ get { return _SelectionRow; }
+ set { _SelectionRow = value; OnPropertyChanged(nameof(SelectionRow), value); }
+ }
+
+ private GanttChartViewItem _SelectionItem = null;
+
+ ///
+ /// 选中的项
+ ///
+ public GanttChartViewItem SelectionItem
+ {
+ get { return _SelectionItem; }
+ set { _SelectionItem = value; OnPropertyChanged(nameof(SelectionItem), value); }
+ }
+
+ private TimeRange _SelectionTimeRange = null;
+
+ ///
+ /// 选中的时间范围
+ ///
+ public TimeRange SelectionTimeRange
+ {
+ get { return _SelectionTimeRange; }
+ set { _SelectionTimeRange = value; OnPropertyChanged(nameof(SelectionTimeRange), value); }
+ }
+
+ private DateTime _DateSplitTime = DateTime.MinValue;
+
+ ///
+ /// 日分割时间
+ ///
+ public DateTime DateSplitTime
+ {
+ get { return _DateSplitTime; }
+ set { _DateSplitTime = value; OnPropertyChanged(nameof(DateSplitTime), value); }
+ }
+
+ private string _DateTimeShowText = "时间";
+
+ ///
+ /// 时间显示文本
+ ///
+ [DefaultValue("时间")]
+ public string DateTimeShowText
+ {
+ get { return _DateTimeShowText; }
+ set { _DateTimeShowText = value; OnPropertyChanged(nameof(DateTimeShowText), value); }
+ }
+
+ private string _RowTitleShowText = "资源";
+
+ ///
+ /// 行头显示文本
+ ///
+ [DefaultValue("资源")]
+ public string RowTitleShowText
+ {
+ get { return _RowTitleShowText; }
+ set { _RowTitleShowText = value; OnPropertyChanged(nameof(RowTitleShowText), value); }
+ }
+ #endregion
+
+ #region ReadOnly
+ public int ColumnHeight
+ {
+ get { return ColumnDateHeight + ColumnHourHeight; }
+ }
+
+ public int TotalDays
+ {
+ get
+ {
+ return (int)(EndDate.Date - StartDate.Date).TotalDays + 1;
+ }
+ }
+ public DateTime StartTime
+ {
+ get
+ {
+ return StartDate.Date.Add(DateSplitTime - DateSplitTime.Date);
+ }
+ }
+ public DateTime EndTime
+ {
+ get
+ {
+ return EndDate.Date.Add(DateSplitTime - DateSplitTime.Date);
+ }
+ }
+ private Size TooltipSize
+ {
+ get
+ {
+ var size = TextRenderer.MeasureText(_ShowTooltipItem.Tooltip, TooltipTextFont, Size.Empty);
+ size.Height = size.Height + (int)((_ShowTooltipItem.Tooltip.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).Length - 1) * 1.7);
+ return size;
+ }
+ }
+ private Size TooltipOuterSize
+ {
+ get
+ {
+ var size = TooltipSize;
+ size.Width += RowSpacing * 2;
+ size.Height += RowSpacing * 2;
+ return size;
+ }
+ }
+ #endregion
+
+ #region Const
+ private const int MinDateWidth = 3 * 48;
+ #endregion
+ }
+}
diff --git a/GanttChart/GanttChartView.Render.cs b/GanttChart/GanttChartView.Render.cs
new file mode 100644
index 0000000..82aad03
--- /dev/null
+++ b/GanttChart/GanttChartView.Render.cs
@@ -0,0 +1,409 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图控件
+ /// 该部分类用于处理甘特图的绘制渲染
+ ///
+ public partial class GanttChartView
+ {
+ ///
+ /// 画背景
+ ///
+ ///
+ ///
+ protected virtual void DrawBack(Graphics graphics, int bottom)
+ {
+ graphics.FillRectangle(this.Brushes.BackBrush, _ContentControl.DisplayRectangle);
+ var range = new RectangleF(new PointF(0, 0), new SizeF(TotalDays * DateWidth + RowHeaderWidth - _HScrollBar.Value, bottom - _VScrollBar.Value));
+ graphics.SetClip(range);
+ graphics.FillRectangle(this.Brushes.HeaderBackBrush, range);
+ range = new RectangleF(new PointF(0, ColumnHeight), new SizeF(TotalDays * DateWidth + RowHeaderWidth - _HScrollBar.Value, bottom - ColumnHeight - _VScrollBar.Value));
+ graphics.FillRectangle(this.Brushes.ContentBackBrush, range);
+ if (_SelectionRow != null)
+ {
+ var selectionHeader = new Rectangle(1, _SelectionRow.Top + 1 - _VScrollBar.Value, RowHeaderWidth - 2, (int)(_SelectionRow.Bottom - _SelectionRow.Top - 1));
+ var selectionContent = new Rectangle(RowHeaderWidth, _SelectionRow.Top + 1 - _VScrollBar.Value, (int)(TotalDays * DateWidth - _HScrollBar.Value - 1), selectionHeader.Height);
+ graphics.FillRectangle(this.Brushes.RowSelectionHeaderBackBrush, selectionHeader);
+ graphics.FillRectangle(this.Brushes.RowSelectionContentBackBrush, selectionContent);
+ }
+ graphics.ResetClip();
+ }
+ ///
+ /// 画没有数据
+ ///
+ ///
+ ///
+ protected virtual void DrawNonData(Graphics graphics, int bottom)
+ {
+
+ }
+ ///
+ /// 画提示框
+ ///
+ ///
+ protected virtual void DrawItemTooltip(Graphics graphics)
+ {
+ if (!_IsShowTooltip) return;
+ var size = TooltipSize;
+ var border = new Rectangle(_ShowTooltipPoint, new Size(size.Width + RowSpacing * 2, size.Height + RowSpacing * 2));
+ var content = new Point(_ShowTooltipPoint.X + RowSpacing, _ShowTooltipPoint.Y + RowSpacing);
+ graphics.FillRectangle(this.Brushes.TooltipBackBrush, border);
+ graphics.DrawRectangle(this.Brushes.TooltipBorderPen, border);
+ graphics.DrawString(_ShowTooltipItem.Tooltip, TooltipTextFont, this.Brushes.TooltipTextBrush, content);
+ //TextRenderer.DrawText(graphics, _ShowTooltipItem.Tooltip, TooltipTextFont, content, TooltipTextColor);
+ }
+ ///
+ /// 画选中范围
+ ///
+ ///
+ protected virtual void DrawSelectionRange(Graphics graphics)
+ {
+ if (!AllowSelectRange || _SelectionRange.IsEmpty) return;
+ graphics.FillRectangle(this.Brushes.TimeRangeSelecetionBackBrush, _SelectionRange);
+ }
+ ///
+ /// 画选中的矩形
+ ///
+ ///
+ protected virtual void DrawSelectingRectangle(Graphics graphics)
+ {
+ if (!AllowSelectRange || _DragStartLocation.IsEmpty || _DragEndLocation.IsEmpty || _DragStartLocation == _DragEndLocation || _DragStartLocation.X <= RowHeaderWidth || _DragStartLocation.Y <= ColumnHeight) return;
+ var row = GetRow(_DragStartLocation);
+ if (row == null) return;
+ var start = new Point(Math.Min(_DragStartLocation.X, Math.Max(_DragEndLocation.X, RowHeaderWidth)), Math.Min(_DragStartLocation.Y, Math.Max(_DragEndLocation.Y, row.Top)));
+ var height = Math.Abs(Math.Min(_DragEndLocation.Y, row.Bottom - _VScrollBar.Value) - _DragStartLocation.Y);
+ var width = Math.Abs(_DragEndLocation.X - _DragStartLocation.X);
+ if (_DragEndLocation.Y < row.Top)
+ {
+ height -= row.Top - _DragEndLocation.Y;
+ }
+ if (_DragEndLocation.X < RowHeaderWidth)
+ {
+ width -= RowHeaderWidth - _DragEndLocation.X;
+ }
+ else if(_DragEndLocation.X > TotalDays * DateWidth + RowHeaderWidth - _HScrollBar.Value)
+ {
+ width = TotalDays * DateWidth + RowHeaderWidth - _HScrollBar.Value - _DragStartLocation.X;
+ }
+ var rect = new RectangleF(start, new SizeF(width, height));
+ graphics.FillRectangle(this.Brushes.SelectionRectangleBackBrush, rect);
+ }
+ ///
+ /// 画项的时间范围
+ ///
+ ///
+ ///
+ ///
+ protected virtual void DrawItemTimeRange(Graphics graphics, GanttChartViewItem item, TimeRange sub)
+ {
+ var width = sub.Width;
+ var right = sub.Left + sub.Width;
+ if (right == item.Left + item.Width)
+ {
+ width = width - 2;
+ if(width < 1)
+ {
+ return;
+ }
+ }
+ if (item == _SelectionItem)
+ {
+ graphics.FillRectangle(this.Brushes.ItemSelectionSubRangeBackBrush, sub.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, width, ItemHeight);
+ graphics.DrawRectangle(this.Brushes.ItemSelectionSubRangeBackPen, sub.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, width, ItemHeight);
+ }
+ else
+ {
+ graphics.FillRectangle(this.Brushes.ItemSubRangeBackBrush, sub.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, width, ItemHeight);
+ graphics.DrawRectangle(this.Brushes.ItemSubRangeBackPen, sub.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, width, ItemHeight);
+ }
+ }
+ ///
+ /// 画项
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected virtual void DrawItem(Graphics graphics, StringFormat titleFormat, GanttChartViewItem item, RectangleF range)
+ {
+ var clip = new RectangleF(range.X, (range.Y < ColumnHeight ? ColumnHeight : range.Y) + 1, range.Width, (range.Y < ColumnHeight ? (range.Height - (ColumnHeight - range.Y)) : range.Height) - 2);
+ graphics.SetClip(clip);
+ if (item.Ranges != null && item.Ranges.Any())
+ {
+ graphics.FillRectangle(this.Brushes.ItemBackBrush, item.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, Math.Max(item.Width - 2, 2), ItemHeight);
+ graphics.DrawRectangle(this.Brushes.ItemBackPen, item.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, Math.Max(item.Width - 2, 2), ItemHeight);
+ var subs = item.Ranges.OrderBy(r => r.StartTime);
+ foreach (var sub in subs)
+ {
+ DrawItemTimeRange(graphics, item, sub);
+ }
+ }
+ else
+ {
+ graphics.FillRectangle(this.Brushes.ItemSubRangeBackBrush, item.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, Math.Max(item.Width - 2, 2), ItemHeight);
+ graphics.DrawRectangle(this.Brushes.ItemSubRangeBackPen, item.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, Math.Max(item.Width - 2, 2), ItemHeight);
+ }
+ if (item == _SelectionItem)
+ {
+ var textBrush = item.IsWarnning ? this.Brushes.ItemWarnningTextBrush : this.Brushes.ItemSelectionTextBrush;
+ graphics.DrawLine(this.Brushes.ItemStartFlagPen, item.Left - _HScrollBar.Value + 1, item.Top - _VScrollBar.Value + ItemHeight / 2, item.Left - _HScrollBar.Value + 1, item.Top - _VScrollBar.Value + ItemHeight);
+ graphics.DrawRectangle(this.Brushes.ItemSelectionBorderPen, item.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, Math.Max(item.Width - 2, 2), ItemHeight);
+ graphics.DrawString(item.Title, ItemTextFont, textBrush, new RectangleF(item.Left - _HScrollBar.Value + 2, item.Top - _VScrollBar.Value + 1, 0, ItemHeight - 2), titleFormat);
+ }
+ else if(_SelectionItem != null && SelectionItemSameComparator != null && SelectionItemSameComparator(item, _SelectionItem))
+ {
+ var textBrush = item.IsWarnning ? this.Brushes.ItemWarnningTextBrush : this.Brushes.ItemSelectionTextBrush;
+ graphics.DrawLine(this.Brushes.ItemStartFlagPen, item.Left - _HScrollBar.Value + 1, item.Top - _VScrollBar.Value + ItemHeight / 2, item.Left - _HScrollBar.Value + 1, item.Top - _VScrollBar.Value + ItemHeight);
+ if (IsShowItemBorder)
+ graphics.DrawRectangle(this.Brushes.ItemBorderPen, item.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, Math.Max(item.Width - 2, 2), ItemHeight);
+ graphics.DrawString(item.Title, ItemTextFont, textBrush, new RectangleF(item.Left - _HScrollBar.Value + 2, item.Top - _VScrollBar.Value + 1, 0, ItemHeight - 2), titleFormat);
+ }
+ else
+ {
+ var textBrush = item.IsWarnning ? this.Brushes.ItemWarnningTextBrush : this.Brushes.ItemTextBrush;
+ graphics.DrawLine(this.Brushes.ItemStartFlagPen, item.Left - _HScrollBar.Value + 1, item.Top - _VScrollBar.Value + ItemHeight / 2, item.Left - _HScrollBar.Value + 1, item.Top - _VScrollBar.Value + ItemHeight);
+ if (IsShowItemBorder)
+ graphics.DrawRectangle(this.Brushes.ItemBorderPen, item.Left - _HScrollBar.Value, item.Top - _VScrollBar.Value, Math.Max(item.Width - 2, 2), ItemHeight);
+ graphics.DrawString(item.Title, ItemTextFont, textBrush, new RectangleF(item.Left - _HScrollBar.Value + 2, item.Top - _VScrollBar.Value + 1, 0, ItemHeight - 2), titleFormat);
+ }
+ graphics.ResetClip();
+ }
+ ///
+ /// 画行
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected virtual void DrawRow(Graphics graphics, StringFormat headerFormat, StringFormat titleFormat, GanttChartViewRow row, RectangleF range, RectangleF rowRect)
+ {
+ graphics.SetClip(range);
+ var drawY = rowRect.Y + RowSpacing;
+ var drawHeight = rowRect.Height - RowSpacing * 2;
+ if (drawHeight > (_ContentControl.Height - ColumnHeight) / 4)
+ {
+ drawY = Math.Max(rowRect.Y, ColumnHeight);
+ drawHeight = Math.Min(rowRect.Bottom - RowSpacing, _ContentControl.Height) - drawY;
+ }
+ graphics.DrawString(row.Title, RowHeaderTextFont, this.Brushes.RowHeaderTextBrush, new RectangleF(rowRect.X + RowSpacing, drawY, RowHeaderWidth - RowSpacing * 2, drawHeight), headerFormat);
+ graphics.ResetClip();
+ if(row.Items != null)
+ {
+ var items = row.Items.OrderBy(r=>r.StartTime);
+ foreach (var item in items)
+ {
+ if (item.Left + item.Width - _HScrollBar.Value > RowHeaderWidth)
+ {
+ if (item.Left - _HScrollBar.Value < range.Right)
+ {
+ DrawItem(graphics, titleFormat, item, new RectangleF(RowHeaderWidth + 1, rowRect.Y + 1, rowRect.Width - RowHeaderWidth - 2, rowRect.Height - 2));
+ }
+ }
+ }
+ }
+ graphics.SetClip(range);
+ graphics.DrawLine(this.Brushes.GridPen, 0, row.Bottom - _VScrollBar.Value, rowRect.Width, row.Bottom - _VScrollBar.Value);
+ if (_SelectionRow == row && IsShowSelectionBorder)
+ {
+ var selectionRect = new Rectangle(1, row.Top + 1, (int)(range.Width - 3), (int)(row.Bottom - row.Top - 2));
+ graphics.DrawRectangle(this.Brushes.RowSelectionBorderPen, selectionRect);
+ }
+ graphics.ResetClip();
+ }
+ ///
+ /// 画所有行
+ ///
+ ///
+ ///
+ protected virtual void DrawRows(Graphics graphics, int bottom)
+ {
+ var range = new RectangleF(0, ColumnHeight, RowHeaderWidth + TotalDays * DateWidth - _HScrollBar.Value, bottom - _VScrollBar.Value + 1);
+ graphics.DrawLine(this.Brushes.GridPen, RowHeaderWidth, ColumnDateHeight, range.Width - 1, ColumnDateHeight);
+ graphics.SetClip(range);
+ graphics.DrawLine(this.Brushes.GridPen, 0, ColumnHeight, range.Width - 1, ColumnHeight);
+ if (Rows == null || !Rows.Any())
+ {
+ DrawNonData(graphics, bottom);
+ graphics.DrawLine(this.Brushes.GridPen, 0, bottom, range.Width - 1, bottom);
+ return;
+ }
+ graphics.ResetClip();
+ var headerFormat = new StringFormat();
+ headerFormat.Alignment = StringAlignment.Near;
+ headerFormat.LineAlignment = StringAlignment.Center;
+ var titleFormat = new StringFormat();
+ titleFormat.Alignment = StringAlignment.Near;
+ titleFormat.LineAlignment = StringAlignment.Center;
+
+ titleFormat.FormatFlags = BlockType == GanttChartViewItemBlockType.Compact ? StringFormatFlags.LineLimit : StringFormatFlags.NoWrap;
+ foreach (var row in Rows)
+ {
+ if (row.Bottom - _VScrollBar.Value > ColumnHeight)
+ {
+ var rowRect = new RectangleF(new PointF(0, row.Top - _VScrollBar.Value), new SizeF(range.Width, row.Bottom - row.Top + 1));
+ if (!range.IntersectsWith(rowRect)) break;
+ DrawRow(graphics, headerFormat, titleFormat, row, range, rowRect);
+ }
+ }
+ }
+ ///
+ /// 画列
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected virtual void DrawColumn(Graphics graphics, StringFormat format, DateTime date, RectangleF range, int startX, int width, int cellHour)
+ {
+ var offsetMinutes = (int)(DateSplitTime - DateSplitTime.Date).TotalMinutes % (60 * cellHour);
+ var offset = (int)(offsetMinutes / 60f * width);
+ startX = startX - offset;
+ var dt = date.AddMinutes(-offsetMinutes);
+ for (DateTime i = dt; i < dt.AddDays(1); i = i.AddHours(cellHour))
+ {
+ var rectangle = new RectangleF(startX, ColumnDateHeight + 1, 0, ColumnHourHeight - 2);
+ if (range.IntersectsWith(rectangle) && (offset != 0 || date.Hour != i.Hour))
+ {
+ graphics.DrawString(i.Hour == 0 ? "0" : i.Hour.ToString("##00"), ColumnDateTextFont, this.Brushes.ColumnHourTextBrush, rectangle, format);
+ //graphics.DrawLine(this.Brushes.GridPen, rectangle.X, ColumnDateHeight, rectangle.X, ColumnDateHeight + ColumnHourHeight / 5);
+ graphics.DrawLine(this.Brushes.GridPen, rectangle.X, ColumnDateHeight + ColumnHourHeight / 5 * 4, rectangle.X, ColumnDateHeight + ColumnHourHeight - 1);
+ }
+ startX += width * cellHour;
+ }
+ }
+ ///
+ /// 画列头
+ ///
+ ///
+ protected virtual void DrawColumnHeader(Graphics graphics)
+ {
+ var range = new RectangleF(new PointF(RowHeaderWidth + 1, 1), new SizeF(TotalDays * DateWidth - 1, _ContentControl.Height - 2));
+ graphics.SetClip(range);
+ int cellHour = GetCellHours();
+ var format = new StringFormat();
+ format.Alignment = StringAlignment.Center;
+ format.LineAlignment = StringAlignment.Center;
+ format.FormatFlags = StringFormatFlags.LineLimit;
+ var x = RowHeaderWidth;
+ for (var i = StartTime; i <= EndTime; i = i.AddDays(1))
+ {
+ var dx = x - _HScrollBar.Value;
+ var rectangle = new RectangleF(dx + 1, 1, DateWidth - 1, ColumnDateHeight - 2);
+ if (rectangle.Right > RowHeaderWidth)
+ {
+ if (!range.IntersectsWith(rectangle))
+ {
+ x += DateWidth;
+ continue;
+ }
+ graphics.DrawString(i.ToString("yyyy-MM-dd") + " 星期" + ("日一二三四五六"[(int)i.DayOfWeek]), ColumnDateTextFont, this.Brushes.ColumnDateTextBrush, rectangle, format);
+ DrawColumn(graphics, format, i, range, (int)rectangle.X - 1, DateWidth / 24, cellHour);
+ }
+ x += DateWidth;
+ }
+ graphics.ResetClip();
+ }
+ ///
+ /// 画行头
+ ///
+ ///
+ ///
+ protected virtual void DrawHeader(Graphics graphics, int bottom)
+ {
+ var range = new RectangleF(new PointF(0, 0), new SizeF(RowHeaderWidth + TotalDays * DateWidth, bottom - _VScrollBar.Value));
+ graphics.SetClip(range);
+ graphics.DrawLine(this.Brushes.GridPen, range.X, range.Y, range.X + RowHeaderWidth, range.Y + ColumnHeight);
+ graphics.DrawString(this.DateTimeShowText, this.ColumnDateTextFont, this.Brushes.ColumnDateTextBrush,
+ new Rectangle(0, 0, RowHeaderWidth - RowSpacing, ColumnDateHeight),
+ new StringFormat { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Center });
+ graphics.DrawString(this.RowTitleShowText, this.RowHeaderTextFont, this.Brushes.RowHeaderTextBrush,
+ new Rectangle(RowSpacing, ColumnDateHeight, RowHeaderWidth - RowSpacing, ColumnHourHeight - RowSpacing),
+ new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Far });
+ graphics.ResetClip();
+ }
+ ///
+ /// 画时间线
+ ///
+ ///
+ ///
+ protected virtual void DrawTimeLine(Graphics graphics, int bottom)
+ {
+ var range = new RectangleF(new PointF(0, 0), new SizeF(RowHeaderWidth + TotalDays * DateWidth, bottom - _VScrollBar.Value));
+ graphics.SetClip(range);
+ graphics.DrawRectangle(this.Brushes.GridPen, _ContentControl.DisplayRectangle);
+ var x = RowHeaderWidth - 1;
+ if(StartTime == DateTime.Today.Add(DateSplitTime - DateSplitTime.Date))
+ {
+ graphics.DrawLine(this.Brushes.CurrentTimeLinePen, x, 0, x, _ContentControl.Height);
+ }
+ else
+ {
+ graphics.DrawLine(this.Brushes.GridPen, x, 0, x, _ContentControl.Height);
+ }
+ for (var i = StartTime; i <= EndTime; i = i.AddDays(1))
+ {
+ x += DateWidth;
+ var dx = x - _HScrollBar.Value;
+ if (dx + 1 > RowHeaderWidth)
+ {
+ if (dx + 1 > _ContentControl.Width) break;
+ if(i.AddDays(1) == DateTime.Today.Add(DateSplitTime - DateSplitTime.Date))
+ {
+ graphics.DrawLine(this.Brushes.CurrentTimeLinePen, dx, 0, dx, _ContentControl.Height);
+ }
+ else
+ {
+ graphics.DrawLine(this.Brushes.GridPen, dx, 0, dx, _ContentControl.Height);
+ }
+ }
+ }
+ graphics.ResetClip();
+ }
+ ///
+ /// 计算单元格小时
+ ///
+ ///
+ private int GetCellHours()
+ {
+ var halfHourWidth = DateWidth / 48;
+ int cellHour;
+ if (halfHourWidth >= 12)
+ {
+ cellHour = 1;
+ }
+ else if (halfHourWidth >= 6)
+ {
+ cellHour = 2;
+ }
+ else if (halfHourWidth >= 4)
+ {
+ cellHour = 3;
+ }
+ else if (halfHourWidth >= 3)
+ {
+ cellHour = 4;
+ }
+ else if (halfHourWidth >= 2)
+ {
+ cellHour = 6;
+ }
+ else
+ {
+ cellHour = 12;
+ }
+ return cellHour;
+ }
+ }
+}
diff --git a/GanttChart/GanttChartView.cs b/GanttChart/GanttChartView.cs
new file mode 100644
index 0000000..96b5231
--- /dev/null
+++ b/GanttChart/GanttChartView.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图控件
+ ///
+ [ToolboxBitmap(typeof(GanttChartView), "GanttChart.GanttChartView.bmp")]
+ public partial class GanttChartView: Control
+ {
+ #region Private Members
+ private HScrollBar _HScrollBar;
+ private VScrollBar _VScrollBar;
+
+ private TableLayoutPanel _Table;
+ private Control _ContentControl;
+
+ private GanttChartBrushes Brushes;
+ #endregion
+
+ #region ctor
+ public GanttChartView()
+ {
+ _Table = new TableLayoutPanel();
+ _Table.ColumnCount = 2;
+ _Table.RowCount = 2;
+ _Table.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
+ _Table.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, VScrollWidth));
+ _Table.RowStyles.Add(new RowStyle(SizeType.AutoSize));
+ _Table.RowStyles.Add(new RowStyle(SizeType.Absolute, HScrollHeight));
+
+ _ContentControl = new GanttChartCanvas();
+ _ContentControl.Dock = DockStyle.Fill;
+ _ContentControl.Margin = new Padding(0);
+ _Table.Controls.Add(_ContentControl, 0, 0);
+
+ _HScrollBar = new HScrollBar();
+ _HScrollBar.Value = 0;
+ _HScrollBar.Height = HScrollHeight;
+ _HScrollBar.SmallChange = 1;
+ _HScrollBar.LargeChange = 2;
+ //_HScrollBar.Dock = DockStyle.Fill;
+ _HScrollBar.Visible = true;
+ _Table.Controls.Add(_HScrollBar, 0, 1);
+
+
+ _VScrollBar = new VScrollBar();
+ _VScrollBar.Value = 0;
+ _VScrollBar.Width = VScrollWidth;
+ _VScrollBar.SmallChange = 1;
+ _VScrollBar.LargeChange = 2;
+ //_VScrollBar.Dock = DockStyle.Fill;
+ _VScrollBar.Visible = true;
+ _Table.Controls.Add(_VScrollBar, 1, 0);
+
+ _Table.Dock = DockStyle.Fill;
+ Controls.Add(_Table);
+
+ InitEvent();
+ }
+
+ #endregion
+ ///
+ /// 调整滚动条
+ ///
+ private void AdjustScrollbar()
+ {
+ var bottom = ItemHeight + RowSpacing * 2;
+ if (Rows != null && Rows.Any())
+ {
+ if (StartDate != Rows.StartDate || Rows.IsChanged)
+ {
+ ComputeRowsAndItemsSize();
+ Rows.IsChanged = false;
+ Rows.StartDate = StartDate;
+ }
+ var last = Rows.Last();
+ bottom = last.Bottom;
+ }
+ if (IsFixedRowHeight)
+ {
+ var h = ColumnHeight + (Rows?.Count ?? 0) * RowHeight + 200;
+ if(h > Height - HScrollHeight)
+ {
+ _VScrollBar.Maximum = h - Height + HScrollHeight + 1;
+ }
+ else
+ {
+ _VScrollBar.Maximum = 0;
+ }
+ }
+ else
+ {
+ _VScrollBar.Maximum = bottom - Height + HScrollHeight + 1 + 200;
+ }
+ _VScrollBar.Minimum = 0;
+
+ _HScrollBar.Maximum = ((int)(EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth - Width + RowHeaderWidth + VScrollWidth + 1 + 200;
+ _HScrollBar.Minimum = 0;
+
+ _VScrollBar.Enabled = _VScrollBar.Maximum > 0;
+ _HScrollBar.Enabled = _HScrollBar.Maximum > 0;
+ }
+ ///
+ /// 重绘
+ ///
+ public new void Invalidate()
+ {
+ base.Invalidate();
+ _ContentControl.Invalidate();
+ }
+ ///
+ /// 销毁
+ ///
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ this.Brushes?.Dispose();
+ base.Dispose(disposing);
+ }
+ class GanttChartCanvas : Control
+ {
+ public GanttChartCanvas()
+ {
+ SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
+ SetStyle(ControlStyles.ResizeRedraw, true);
+ SetStyle(ControlStyles.Selectable, true);
+ }
+ protected override void OnPaintBackground(PaintEventArgs pevent) { }
+ }
+ }
+}
diff --git a/GanttChart/GanttChartViewColumn.cs b/GanttChart/GanttChartViewColumn.cs
new file mode 100644
index 0000000..b43a587
--- /dev/null
+++ b/GanttChart/GanttChartViewColumn.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ public class GanttChartViewColumn
+ {
+ }
+}
diff --git a/GanttChart/GanttChartViewColumnGroup.cs b/GanttChart/GanttChartViewColumnGroup.cs
new file mode 100644
index 0000000..41aba2c
--- /dev/null
+++ b/GanttChart/GanttChartViewColumnGroup.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ public class GanttChartViewColumnGroup
+ {
+ }
+}
diff --git a/GanttChart/GanttChartViewItem.cs b/GanttChart/GanttChartViewItem.cs
new file mode 100644
index 0000000..809baf8
--- /dev/null
+++ b/GanttChart/GanttChartViewItem.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图项
+ ///
+ public class GanttChartViewItem : TimeRange
+ {
+ ///
+ /// 项的时间范围集合
+ ///
+ public ICollection Ranges { get; set; }
+ ///
+ /// 标题
+ ///
+ public string Title { get; set; }
+ ///
+ /// 提示内容
+ ///
+ public string Tooltip { get; set; }
+ ///
+ /// 顶部位置
+ ///
+ internal int Top { get; set; }
+ ///
+ /// 文本宽度
+ ///
+ internal int TextWidth { get; set; }
+ ///
+ /// 数据
+ ///
+ public object Data { get; set; }
+ ///
+ /// 是否警告
+ ///
+ public bool IsWarnning { get; set; }
+ }
+}
diff --git a/GanttChart/GanttChartViewItemBlockType.cs b/GanttChart/GanttChartViewItemBlockType.cs
new file mode 100644
index 0000000..5f90170
--- /dev/null
+++ b/GanttChart/GanttChartViewItemBlockType.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图项的换行模式
+ ///
+ public enum GanttChartViewItemBlockType
+ {
+ ///
+ /// 紧凑
+ ///
+ Compact,
+ ///
+ /// 文字超过换行
+ ///
+ TextOverBlock,
+ ///
+ /// 强制换行
+ ///
+ Block,
+ ///
+ /// 回归
+ ///
+ Return
+ }
+}
diff --git a/GanttChart/GanttChartViewRow.cs b/GanttChart/GanttChartViewRow.cs
new file mode 100644
index 0000000..2e87b4b
--- /dev/null
+++ b/GanttChart/GanttChartViewRow.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 甘特图行
+ ///
+ public class GanttChartViewRow
+ {
+ ///
+ /// 标题
+ ///
+ public string Title { get; set; }
+ ///
+ /// 顶部
+ ///
+ internal int Top { get; set; }
+ ///
+ /// 按钮
+ ///
+ internal int Bottom { get; set; }
+ ///
+ /// 项集合
+ ///
+ public List Items { get; set; }
+ }
+}
diff --git a/GanttChart/Properties/AssemblyInfo.cs b/GanttChart/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d8d03c1
--- /dev/null
+++ b/GanttChart/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("GanttChart")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("GanttChart")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("dea91cb9-1011-4ee7-b8e1-72428f731789")]
+
+// 程序集的版本信息由下列四个值组成:
+//
+// 主版本
+// 次版本
+// 生成号
+// 修订号
+//
+//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/GanttChart/Properties/Resources.Designer.cs b/GanttChart/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..da1a28c
--- /dev/null
+++ b/GanttChart/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本:4.0.30319.42000
+//
+// 对此文件的更改可能会导致不正确的行为,并且如果
+// 重新生成代码,这些更改将会丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace GanttChart.Properties {
+ using System;
+
+
+ ///
+ /// 一个强类型的资源类,用于查找本地化的字符串等。
+ ///
+ // 此类是由 StronglyTypedResourceBuilder
+ // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+ // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+ // (以 /str 作为命令选项),或重新生成 VS 项目。
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// 返回此类使用的缓存的 ResourceManager 实例。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GanttChart.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// 重写当前线程的 CurrentUICulture 属性,对
+ /// 使用此强类型资源类的所有资源查找执行重写。
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/GanttChart/Properties/Resources.resx b/GanttChart/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/GanttChart/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/GanttChart/Properties/Settings.Designer.cs b/GanttChart/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..9879631
--- /dev/null
+++ b/GanttChart/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// 此代码由工具生成。
+// 运行时版本:4.0.30319.42000
+//
+// 对此文件的更改可能会导致不正确的行为,并且如果
+// 重新生成代码,这些更改将会丢失。
+//
+//------------------------------------------------------------------------------
+
+namespace GanttChart.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.12.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/GanttChart/Properties/Settings.settings b/GanttChart/Properties/Settings.settings
new file mode 100644
index 0000000..3964565
--- /dev/null
+++ b/GanttChart/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/GanttChart/TimeRange.cs b/GanttChart/TimeRange.cs
new file mode 100644
index 0000000..c7458f2
--- /dev/null
+++ b/GanttChart/TimeRange.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace GanttChart
+{
+ ///
+ /// 时间范围
+ ///
+ public class TimeRange
+ {
+ ///
+ /// 开始时间
+ ///
+ public DateTime StartTime { get; set; }
+ ///
+ /// 结束时间
+ ///
+ public DateTime EndTime { get; set; }
+ ///
+ /// 左边
+ ///
+ internal int Left { get; set; }
+ ///
+ /// 宽度
+ ///
+ internal int Width { get; set; }
+ }
+}
diff --git a/SunlightCentralizedControlManagement(SCCM).sln b/SunlightCentralizedControlManagement(SCCM).sln
index 708ea7a..24208a7 100644
--- a/SunlightCentralizedControlManagement(SCCM).sln
+++ b/SunlightCentralizedControlManagement(SCCM).sln
@@ -5,6 +5,8 @@ VisualStudioVersion = 17.11.35312.102
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SunlightCentralizedControlManagement_SCCM_", "SunlightCentralizedControlManagement_SCCM_.csproj", "{2CFE8A79-C7DC-47AC-8D0C-2E03010E2458}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GanttChart", "GanttChart\GanttChart.csproj", "{DEA91CB9-1011-4EE7-B8E1-72428F731789}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
{2CFE8A79-C7DC-47AC-8D0C-2E03010E2458}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2CFE8A79-C7DC-47AC-8D0C-2E03010E2458}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2CFE8A79-C7DC-47AC-8D0C-2E03010E2458}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DEA91CB9-1011-4EE7-B8E1-72428F731789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DEA91CB9-1011-4EE7-B8E1-72428F731789}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DEA91CB9-1011-4EE7-B8E1-72428F731789}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DEA91CB9-1011-4EE7-B8E1-72428F731789}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/View/ProductionPlanningView.xaml b/View/ProductionPlanningView.xaml
index 602813f..44eb6ed 100644
--- a/View/ProductionPlanningView.xaml
+++ b/View/ProductionPlanningView.xaml
@@ -22,6 +22,7 @@
+
diff --git a/View/ProductionPlanningView.xaml.cs b/View/ProductionPlanningView.xaml.cs
index c8ddecd..19bbf14 100644
--- a/View/ProductionPlanningView.xaml.cs
+++ b/View/ProductionPlanningView.xaml.cs
@@ -30,6 +30,8 @@ using static SunlightCentralizedControlManagement_SCCM_.UserClass.SqliteHelper;
using static SunlightCentralizedControlManagement_SCCM_.WindowsView.ViewStep;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using SunlightCentralizedControlManagement_SCCM_.ViewModel;
+using LiveChartsCore.SkiaSharpView.WPF;
+using System.Data.Entity.Core.Common.CommandTrees.ExpressionBuilder;
namespace SunlightCentralizedControlManagement_SCCM_.View
{
@@ -64,8 +66,6 @@ namespace SunlightCentralizedControlManagement_SCCM_.View
webBrowser.NavigateToString(html);
-
-
}
private void ListViewItem_Quit(object sender, System.Windows.Input.MouseButtonEventArgs e)//退出事件