Instantly share code, notes, and snippets.
Last active
September 25, 2023 22:53
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save KOZ60/79f6faed9468136e49696adf04b9776e to your computer and use it in GitHub Desktop.
DataGridViewWithFooter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Drawing; | |
using System.Windows.Forms; | |
[DesignerCategory("code") ] | |
public class DataGridViewWithFooter : DataGridView | |
{ | |
private readonly FotterControl fotterPanel; | |
public DataGridViewWithFooter() { | |
DoubleBuffered = true; | |
fotterPanel = CreateFotterControl(); | |
} | |
// Properties | |
[DefaultValue(22)] | |
public int FootersHeight { get; set; } = 22; | |
[DefaultValue(true)] | |
public bool FootersVisble { | |
get { | |
return fotterPanel.Visible; | |
} | |
set { | |
fotterPanel.Visible = value; | |
} | |
} | |
// Events | |
public event DataGridViewCellPaintingEventHandler PaintFooterCell; | |
protected virtual void OnPaintFooterCell(DataGridViewCellPaintingEventArgs e) { | |
PaintFooterCell?.Invoke(this, e); | |
} | |
// For inheritance | |
protected virtual FotterControl CreateFotterControl() { | |
return new FotterControl(this); | |
} | |
// Control that displays footer | |
protected class FotterControl : Control | |
{ | |
private readonly DataGridViewWithFooter Owner; | |
public FotterControl(DataGridViewWithFooter onwer) { | |
Owner = onwer; | |
Visible = true; | |
Owner.Controls.Add(this); | |
SendToBack(); | |
SetStyle(ControlStyles.ResizeRedraw | | |
ControlStyles.AllPaintingInWmPaint | | |
ControlStyles.OptimizedDoubleBuffer, true); | |
} | |
protected void DrawVirtiacalLine(Graphics g, Pen pen, | |
Rectangle gridRect, int pos) { | |
g.SetClip(gridRect); | |
g.DrawLine(pen, pos, gridRect.Top, pos, gridRect.Bottom); | |
} | |
protected override void OnPaint(PaintEventArgs e) { | |
base.OnPaint(e); | |
Rectangle gridRect = ClientRectangle; | |
Rectangle columnRect = gridRect; | |
if (Owner.RowHeadersVisible) { | |
columnRect.Width -= Owner.RowHeadersWidth; | |
columnRect.X += Owner.RowHeadersWidth; | |
} | |
Graphics g = e.Graphics; | |
if (gridRect.Width > 0 && gridRect.Height > 0) { | |
using (var brush = new SolidBrush(BackColor)) { | |
g.FillRectangle(brush, gridRect); | |
} | |
using (var pen = new Pen(Owner.BackgroundColor)) { | |
// Columns | |
using (var enumerator = new ColumnLayoutEnumerator(Owner)) { | |
while (enumerator.MoveNext()) { | |
var current = enumerator.Current; | |
DrawVirtiacalLine(g, pen, gridRect, current.Right - 1); | |
var cellBounds = Rectangle.FromLTRB( | |
current.Left, gridRect.Top + 1, | |
current.Right, gridRect.Bottom | |
); | |
var clipBounds = Rectangle.FromLTRB( | |
current.ClipLeft, gridRect.Top + 1, | |
current.Right, gridRect.Bottom | |
); | |
clipBounds = Rectangle.Intersect(clipBounds, columnRect); | |
g.SetClip(clipBounds); | |
var fe = new DataGridViewCellPaintingEventArgs( | |
Owner, | |
e.Graphics, | |
clipBounds, | |
cellBounds, | |
-1, | |
current.ColumnIndex, | |
DataGridViewElementStates.Displayed, | |
null, | |
null, | |
null, | |
new DataGridViewCellStyle(), | |
new DataGridViewAdvancedBorderStyle(), | |
DataGridViewPaintParts.All); | |
Owner.OnPaintFooterCell(fe); | |
} | |
} | |
// Draw FooterRowHeader | |
g.SetClip(gridRect); | |
g.DrawRectangle(pen, gridRect); | |
DrawVirtiacalLine(g, pen, gridRect, 1); | |
if (Owner.RowHeadersVisible) { | |
DrawVirtiacalLine(g, pen, gridRect, Owner.RowHeadersWidth); | |
} | |
using (var boldPen = new Pen(Color.Black, 2)) { | |
e.Graphics.DrawLine(boldPen, | |
gridRect.Left, gridRect.Top - 1, | |
gridRect.Left, gridRect.Bottom); | |
} | |
} | |
} | |
} | |
} | |
protected override void OnPaint(PaintEventArgs e) { | |
base.OnPaint(e); | |
fotterPanel.Bounds = FooterRectangle; | |
} | |
protected override void OnColumnRemoved(DataGridViewColumnEventArgs e) { | |
base.OnColumnRemoved(e); | |
fotterPanel.Invalidate(); | |
} | |
protected override void OnColumnAdded(DataGridViewColumnEventArgs e) { | |
base.OnColumnAdded(e); | |
fotterPanel.Invalidate(); | |
} | |
protected override void OnColumnWidthChanged(DataGridViewColumnEventArgs e) { | |
base.OnColumnWidthChanged(e); | |
fotterPanel.Invalidate(); | |
} | |
protected override void OnSizeChanged(EventArgs e) { | |
base.OnSizeChanged(e); | |
fotterPanel.Invalidate(); | |
} | |
protected override void OnScroll(ScrollEventArgs e) { | |
base.OnScroll(e); | |
fotterPanel.Invalidate(); | |
} | |
// Mouse Handler | |
protected override void OnMouseDown(MouseEventArgs e) { | |
base.OnMouseDown(e); | |
// Turn off DoubleBuffered to show SplitBar | |
DoubleBuffered = false; | |
if (Capture) { | |
SetCursorClip(); | |
fotterPanel.Refresh(); | |
} | |
} | |
protected override void OnMouseUp(MouseEventArgs e) { | |
base.OnMouseUp(e); | |
// Turn on DoubleBuffered | |
DoubleBuffered = true; | |
fotterPanel.Refresh(); | |
Cursor.Clip = Rectangle.Empty; | |
} | |
protected override void OnMouseMove(MouseEventArgs e) { | |
base.OnMouseMove(e); | |
if (Capture) { | |
SetCursorClip(); | |
fotterPanel.Refresh(); | |
} | |
} | |
// set mouse movement range | |
protected virtual void SetCursorClip() { | |
if (FootersVisble) { | |
Rectangle clip = Cursor.Clip; | |
if (!clip.IsEmpty) { | |
int bottom = fotterPanel.PointToScreen(Point.Empty).Y; | |
if (clip.Bottom > bottom) { | |
Cursor.Clip = Rectangle.FromLTRB(clip.Left, clip.Top, | |
clip.Right, bottom); | |
} | |
} | |
} | |
} | |
protected Rectangle FooterRectangle { | |
get { | |
// top,bottom | |
Rectangle d = DisplayRectangle; | |
int top; | |
int bottom; | |
if (HorizontalScrollBar.Visible) { | |
bottom = HorizontalScrollBar.Top; | |
} else { | |
bottom = d.Bottom - 2; | |
} | |
top = bottom - FootersHeight; | |
// left,right | |
int left = 0; | |
int right = 0; | |
using (var enumerator = new ColumnLayoutEnumerator(this)) { | |
while (enumerator.MoveNext()) { | |
right = enumerator.Current.Right; | |
} | |
} | |
right = Math.Min(DisplayRectangle.Right - 1, right); | |
if (VerticalScrollBar.Visible) { | |
right = Math.Min(VerticalScrollBar.Left - 1, right); | |
} | |
return Rectangle.FromLTRB( | |
left, top, right, bottom); | |
} | |
} | |
protected readonly struct ColumnLayout | |
{ | |
public readonly int ColumnIndex; | |
public readonly int ClipLeft; | |
public readonly int Left; | |
public readonly int Right; | |
public ColumnLayout(int columnIndex, | |
int clipLeft, int left, int right) { | |
ColumnIndex = columnIndex; | |
ClipLeft = clipLeft; | |
Left = left; | |
Right = right; | |
} | |
} | |
// For Layout | |
protected class ColumnLayoutEnumerator : IEnumerator<ColumnLayout> | |
{ | |
private DataGridViewWithFooter Owner; | |
private DataGridViewColumn column; | |
private ColumnLayout current; | |
private int clipLeft; | |
private bool colFrozen; | |
public ColumnLayoutEnumerator(DataGridViewWithFooter owner) { | |
Owner = owner; | |
Reset(); | |
} | |
public void Reset() { | |
column = Owner.Columns.GetFirstColumn( | |
DataGridViewElementStates.Displayed); | |
colFrozen = true; | |
clipLeft = Owner.DisplayRectangle.Left + 1; | |
if (Owner.RowHeadersVisible) { | |
clipLeft += Owner.RowHeadersWidth; | |
} | |
} | |
public ColumnLayout Current => current; | |
public void Dispose() { | |
Owner = null; | |
column = null; | |
} | |
public bool MoveNext() { | |
if (column == null) { | |
return false; | |
} | |
int left = clipLeft; | |
int right = clipLeft + column.Width; | |
// first unfrozen column is left side hidden. | |
bool unFrozen = !column.State.HasFlag(DataGridViewElementStates.Frozen); | |
if (unFrozen && colFrozen) { | |
colFrozen = false; | |
left -= Owner.FirstDisplayedScrollingColumnHiddenWidth; | |
right -= Owner.FirstDisplayedScrollingColumnHiddenWidth; | |
} | |
// make current | |
current = new ColumnLayout(column.Index, | |
clipLeft, left, right); | |
clipLeft = right; | |
column = Owner.Columns.GetNextColumn(column, | |
DataGridViewElementStates.Displayed, | |
DataGridViewElementStates.None); | |
return true; | |
} | |
object IEnumerator.Current => current; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment