이전 시간에 일/주차/년월 정보의 Header를 구성하는 YearMonthWeekNoDayHeader.cs 파일 설정과 내용을 살펴 보았다. 오늘은 실제 일/주차/년월 정보의 Header를 그리는 YearMonthWeekNoDayHeaderGenerator.cs 파일을 살펴보기로 하자.
실제 WANIGrid의 Header 영역을 직접 생성하는 클래스 중 기본 WANIGrid의 Header를 생성하는 클래스인 DefaultHeaderGenerator.cs를 살펴 보았다.
이번에는 일/주차/년월 Header를 생성하는 YearMonthWeekNoDayHeaderGenerator.cs를 만들어 볼 것이다.
YearMonthWeekNoDayHeaderGenerator클래스는 HeaderGenerator클래스를 상속 받아서 구현한다.
YearMonthWeekNoDayHeaderGenerator클래스에는 고정 컬럼이 있을 경우와 없을 경우의 DrawHeaders라는 메소드외에 몇몇 메소드들을 재정의해서 Header영역을 그리는 부분을 구현해야 한다.
public class YearMonthWeekNoDayHeaderGenerator : HeaderGenerator
{
#region 생성자
public YearMonthWeekNoDayHeaderGenerator()
{
TopHeaderHeight = 60;
this._headers.Clear();
}
#endregion 생성자
public override void AddHeaders(object obj)
{
this._headers.Add(obj as Header);
}
public override List GetHeaders()
{
return this._headers;
}
public override void HeaderClear()
{
this._headers.Clear();
}
//고정컬럼이 없을 경우 Header 그리기
public override void DrawHeaders(int firstVisibleCol, int lastVisibleCol, int controlWidth, Graphics graphics, Rectangle rect)
{
SolidBrush brush = new SolidBrush(SystemColors.ControlLight);
Pen pen = new Pen(Color.LightGray);
int columnStartX = 0;
int calendarStartX = 0;
graphics.FillRectangle(brush, columnStartX + 1, 1, leftHeaderWidth, topHeaderHeight);
graphics.DrawRectangle(pen, columnStartX + 1, 1, leftHeaderWidth, topHeaderHeight);
columnStartX += leftHeaderWidth; //첫 시작컬럼의 폭을 leftHeaderWidth 만큼 설정
//주차 기간을 저장하기 위한 Dictionary - width 계산을 위해 필요
Dictionary<int, List> dicWeekNo = new Dictionary<int, List>();
//년월 기간을 저장하기 위한 Dictionary - width 계산을 위해 필요
Dictionary<string, List> dicYearMonth = new Dictionary<string, List>();
for (int i = firstVisibleCol; i <= lastVisibleCol; i++)
{
if (!this._headers[i].Visible) continue;
int headerWidth = this._headers[i].Width; //i 번째 컬럼의 폭을 설정
//보여지는 컬럼의 폭이 컨트롤의 폭 보다 클경우
if (columnStartX + headerWidth > controlWidth)
{
headerWidth = controlWidth - columnStartX - 3;
if (lastVisibleCol == (this._headers.Count - 1)) IsLargeLastCol = true;
}
else
{
IsLargeLastCol = false;
}
YearMonthWeekNoDayHeader yearMonthHeader = this._headers[i] as YearMonthWeekNoDayHeader;
if (yearMonthHeader.GetDateTime <= DateTime.MinValue)
{
//Grid Header를 그린다.
DrawTextUtil.DrawGridHeaderRectangleAndText(graphics, brush, blackBrush, pen, this._headers, headerFont,
i, columnStartX, headerWidth, topHeaderHeight);
}
else
{
if (calendarStartX == 0) calendarStartX = columnStartX;
//Calendar 날짜 형태의 컬럼 Header 그리기(일)
DrawTextUtil.DrawGridHeaderCalendarRectangleAndText(graphics, brush, blackBrush, pen,
this._headers, headerFont, i, columnStartX, headerWidth);
if (!dicWeekNo.ContainsKey(yearMonthHeader.WeekNumber)) dicWeekNo.Add(yearMonthHeader.WeekNumber, new List());
if (yearMonthHeader.Visible) dicWeekNo[yearMonthHeader.WeekNumber].Add(yearMonthHeader.Width);
if (!dicYearMonth.ContainsKey(yearMonthHeader.YearMonth)) dicYearMonth.Add(yearMonthHeader.YearMonth, new List());
if (yearMonthHeader.Visible) dicYearMonth[yearMonthHeader.YearMonth].Add(yearMonthHeader.Width);
}
columnStartX += headerWidth;
}
//Calendar 날짜 형태의 컬럼 Header 그리기(주차/년월)
DrawTextUtil.DrawGridHeaderCalendarWeekNumberRectangleAndText(graphics, brush, blackBrush, pen,
headerFont, dicWeekNo, calendarStartX);
DrawTextUtil.DrawGridHeaderCalendarYearMonthRectangleAndText(graphics, brush, blackBrush, pen,
headerFont, dicYearMonth, calendarStartX);
}
//고정컬럼이 있을 경우 Header 그리기
public override void DrawHeaders(int colFixed, int firstVisibleCol, int lastVisibleCol, int controlWidth, Graphics graphics,
Rectangle rect, bool fixedColEditable)
{
SolidBrush brush = new SolidBrush(SystemColors.ControlLight);
Pen pen = new Pen(Color.LightGray);
int columnStartX = 0;
int calendarStartX = 0;
graphics.FillRectangle(brush, columnStartX + 1, 1, leftHeaderWidth, topHeaderHeight);
graphics.DrawRectangle(pen, columnStartX + 1, 1, leftHeaderWidth, topHeaderHeight);
columnStartX += leftHeaderWidth; //첫 시작컬럼의 폭을 leftHeaderWidth 만큼 설정
int fixCol = this.GetLastFixedCol(colFixed);
//주차 기간을 저장하기 위한 Dictionary - width 계산을 위해 필요
Dictionary<int, List> dicWeekNo = new Dictionary<int, List>();
//년월 기간을 저장하기 위한 Dictionary - width 계산을 위해 필요
Dictionary<string, List> dicYearMonth = new Dictionary<string, List>();
for (int i = 0; i <= fixCol; i++)
{
if (!this._headers[i].Visible) continue;
int headerWidth = this._headers[i].Width; //i 번째 컬럼의 폭을 설정
//고정컬럼 수정여부 확인
if (!fixedColEditable) this._headers[i].Editable = false;
//보여지는 컬럼의 폭이 컨트롤의 폭 보다 클경우
if (columnStartX + headerWidth > controlWidth)
{
headerWidth = controlWidth - columnStartX - 3;
if (lastVisibleCol == (this._headers.Count - 1)) IsLargeLastCol = true;
}
else
{
IsLargeLastCol = false;
}
YearMonthWeekNoDayHeader yearMonthHeader = this._headers[i] as YearMonthWeekNoDayHeader;
DrawTextUtil.DrawGridHeaderRectangleAndText(graphics, brush, blackBrush, pen, this._headers, headerFont,
i, columnStartX, headerWidth, topHeaderHeight);
columnStartX += headerWidth;
}
for (int i = firstVisibleCol + fixCol + 1; i <= lastVisibleCol && i < this._headers.Count; i++)
{
if (!this._headers[i].Visible) continue;
int headerWidth = this._headers[i].Width; //i 번째 컬럼의 폭을 설정
//보여지는 컬럼의 폭이 컨트롤의 폭 보다 클경우
if (columnStartX + headerWidth > controlWidth)
{
headerWidth = controlWidth - columnStartX - 3;
if (lastVisibleCol == (this._headers.Count - 1)) IsLargeLastCol = true;
}
else
{
IsLargeLastCol = false;
}
YearMonthWeekNoDayHeader yearMonthHeader = this._headers[i] as YearMonthWeekNoDayHeader;
if (yearMonthHeader.GetDateTime <= DateTime.MinValue)
{
//Grid Header를 그린다.
DrawTextUtil.DrawGridHeaderRectangleAndText(graphics, brush, blackBrush, pen, this._headers, headerFont,
i, columnStartX, headerWidth, topHeaderHeight);
}
else //Calendar 날짜 형태의 컬럼을 그리기 위한 사전 준비
{
if (calendarStartX == 0) calendarStartX = columnStartX;
if (!dicWeekNo.ContainsKey(yearMonthHeader.WeekNumber)) dicWeekNo.Add(yearMonthHeader.WeekNumber, new List());
if (yearMonthHeader.Visible) dicWeekNo[yearMonthHeader.WeekNumber].Add(yearMonthHeader.Width);
if (!dicYearMonth.ContainsKey(yearMonthHeader.YearMonth)) dicYearMonth.Add(yearMonthHeader.YearMonth, new List());
if (yearMonthHeader.Visible) dicYearMonth[yearMonthHeader.YearMonth].Add(yearMonthHeader.Width);
//Calendar 날짜 형태의 컬럼 Header 그리기(일)
DrawTextUtil.DrawGridHeaderCalendarRectangleAndText(graphics, brush, blackBrush, pen, this._headers, headerFont,
i, columnStartX, headerWidth);
}
columnStartX += headerWidth;
}
//Calendar 날짜 형태의 컬럼 Header 그리기(주차/년월)
DrawTextUtil.DrawGridHeaderCalendarWeekNumberRectangleAndText(graphics, brush, blackBrush, pen,
headerFont, dicWeekNo, calendarStartX);
DrawTextUtil.DrawGridHeaderCalendarYearMonthRectangleAndText(graphics, brush, blackBrush, pen,
headerFont, dicYearMonth, calendarStartX);
}
}
실제 Header 영역에 text를 출력하기 위한 DrawTextUtil이라는 클래스를 추가한다.
DrawTextUtil 클래스는 Header영역의 텍스트를 출력하기 위한 클래스로 헤드 영역의 Rectangle 사이즈에 맞는 폰트 사이즈를 계산해서 적정한 크기의 Header Title을 출력하는 역할을 한다.
public static class DrawTextUtil
{
/// Grid Header를 그린다.
public static void DrawGridHeaderRectangleAndText(Graphics graphics, SolidBrush brush, SolidBrush blackBrush, Pen pen,
List headers, Font headerFont, int index, int columnStartX, int headerWidth, int topHeaderHeight)
{
if (headerWidth == 0) return;
//헤더영역의 사각형을 채우고 테두리를 그린다.
graphics.FillRectangle(brush, columnStartX + 1, 1, headerWidth, topHeaderHeight);
graphics.DrawRectangle(pen, columnStartX + 1, 1, headerWidth, topHeaderHeight);
//헤더 타이틀 정렬 방법 설정
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringUtil.GetStringAlignment(sf, HorizontalAlignment.Center);
//헤더 타이틀을 그린다.
Rectangle colRec = new Rectangle(columnStartX + 1, 1, headerWidth, topHeaderHeight);
if (headers == null)
{
graphics.DrawString("", headerFont, blackBrush, colRec, sf);
}
else
{
graphics.DrawString(headers[index].Title, headerFont, blackBrush, colRec, sf);
}
}
/// Grid Calendar Day Header를 그린다.
public static void DrawGridHeaderCalendarRectangleAndText(Graphics graphics, SolidBrush brush, SolidBrush blackBrush, Pen pen,
List headers, Font headerFont, int index, int columnStartX, int headerWidth)
{
//일자 출력
if (headerWidth == 0) return;
int dayYLocation = 32;
int dayHeight = 28;
//헤더영역의 사각형을 채우고 테두리를 그린다.
graphics.FillRectangle(brush, columnStartX + 1, dayYLocation + 1, headerWidth, dayHeight);
graphics.DrawRectangle(pen, columnStartX + 1, dayYLocation + 1, headerWidth, dayHeight);
//헤더 타이틀 정렬 방법 설정
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringUtil.GetStringAlignment(sf, HorizontalAlignment.Center);
//헤더 타이틀을 그린다.
Rectangle colRec = new Rectangle(columnStartX + 1, dayYLocation + 1, headerWidth, dayHeight);
Rectangle colRec1 = new Rectangle(columnStartX + 1, dayYLocation + 1, headerWidth, dayHeight / 2);
Rectangle colRec2 = new Rectangle(columnStartX + 1, dayYLocation + (dayHeight / 2) + 1, headerWidth, dayHeight / 2);
if (headers == null)
{
graphics.DrawString("", headerFont, blackBrush, colRec, sf);
}
else
{
if (headers[index].Width >= 5 && headers[index].Width < 15)
{
Font dayFont = CalculateFontSize(graphics, headers[index].Title.Substring(0, 1), headerFont, columnStartX,
dayYLocation, headerWidth, dayHeight);
if (dayFont.Size > 8.3) dayFont = new Font(headerFont.Name, 8.4f);
graphics.DrawString(headers[index].Title.Substring(0,1), dayFont, blackBrush, colRec1, sf);
graphics.DrawString(headers[index].Title.Substring(1,1), dayFont, blackBrush, colRec2, sf);
} else
{
Font calHeadFont = CalculateFontSize(graphics, headers[index].Title, headerFont, columnStartX, dayYLocation,
headerWidth, dayHeight);
if (calHeadFont.Size > 8.3) calHeadFont = new Font(headerFont.Name, 8.4f);
graphics.DrawString(headers[index].Title, calHeadFont, blackBrush, colRec, sf);
}
}
}
/// Grid Calendar Week Number Header를 그린다.
public static void DrawGridHeaderCalendarWeekNumberRectangleAndText(Graphics graphics, SolidBrush brush, SolidBrush blackBrush,
Pen pen, Font headerFont, Dictionary<int, List> dicWeekNo, int columnStartX)
{
int dayYLocation = 16;
int weekNoHeight = 16;
foreach (KeyValuePair<int, List> items in dicWeekNo)
{
int weekWidth = items.Value.Sum();
//헤더영역의 사각형을 채우고 테두리를 그린다.
graphics.FillRectangle(brush, columnStartX + 1, dayYLocation + 1, weekWidth, weekNoHeight);
graphics.DrawRectangle(pen, columnStartX + 1, dayYLocation + 1, weekWidth, weekNoHeight);
//헤더 타이틀 정렬 방법 설정
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringUtil.GetStringAlignment(sf, HorizontalAlignment.Center);
//헤더 타이틀을 그린다.
Rectangle colRec = new Rectangle(columnStartX + 1, dayYLocation + 1, weekWidth, weekNoHeight);
//적절한 폰트 사이즈를 계산
Font calHeadFont = CalculateFontSize(graphics, items.Key.ToString(), headerFont, columnStartX, dayYLocation,
weekWidth, weekNoHeight);
graphics.DrawString(items.Key.ToString(), calHeadFont, blackBrush, colRec, sf);
columnStartX += weekWidth;
}
}
/// Grid Calendar Year Month Header를 그린다.
public static void DrawGridHeaderCalendarYearMonthRectangleAndText(Graphics graphics, SolidBrush brush, SolidBrush blackBrush,
Pen pen, Font headerFont, Dictionary<string, List> dicYearMonth, int columnStartX)
{
int dayYLocation = 0;
int weekNoHeight = 16;
foreach (KeyValuePair<string, List> items in dicYearMonth)
{
int yearMonthWidth = items.Value.Sum();
//헤더영역의 사각형을 채우고 테두리를 그린다.
graphics.FillRectangle(brush, columnStartX + 1, dayYLocation + 1, yearMonthWidth, weekNoHeight);
graphics.DrawRectangle(pen, columnStartX + 1, dayYLocation + 1, yearMonthWidth, weekNoHeight);
//헤더 타이틀 정렬 방법 설정
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringUtil.GetStringAlignment(sf, HorizontalAlignment.Center);
//헤더 타이틀을 그린다.
Rectangle colRec = new Rectangle(columnStartX + 1, dayYLocation + 1, yearMonthWidth, weekNoHeight);
Font calHeadFont = CalculateFontSize(graphics, items.Key.ToString(), headerFont, columnStartX, dayYLocation,
yearMonthWidth, weekNoHeight);
graphics.DrawString(items.Key.ToString(), calHeadFont, blackBrush, colRec, sf);
columnStartX += yearMonthWidth;
}
}
/// 사각형 사이즈에 맞는 폰트 크기를 계산한다.
public static Font CalculateFontSize(Graphics g, string header, Font headerFont, int columnStartX, int columnStartY,
int headerWidth, int headerHeight)
{
Single Factor, FactorX, FactorY;
Rectangle rec = new Rectangle(columnStartX + 1, columnStartY + 1, headerWidth, headerHeight);
SizeF sz = g.MeasureString(header, headerFont);
FactorX = headerWidth / sz.Width;
FactorY = headerHeight / sz.Height;
if (FactorX > FactorY) Factor = FactorY;
else Factor = FactorX;
if (Factor > 0)
return new Font(headerFont.Name, headerFont.SizeInPoints * Factor);
else
return new Font(headerFont.Name, headerFont.SizeInPoints * 0.1f);
}
}
추가된 YearMonthWeekNoDayHeaderGenerator 클래스를 반영하기 위해 Grid 클래스(Grid.cs)에서 추가 및 보완해야 할 부분을 살펴보자.
YearMonthWeekNoDayHeaderGenerator 영역에서 헤더 영역의 주차/년월 정보를 그리기 위해서 생성했던 Dictionary 변수를 Grid클래스를 통해서 접근할 수 있도록 변수 및 속성(Property)를 추가한다.
private Dictionary<int, List> dicWeekDay = null; //주차
private Dictionary<string, List> dicMonthDay = null; //년월
public Dictionary<int, List> DicWeekDay
{
get { return dicWeekDay; }
set { dicWeekDay = value; }
}
public Dictionary<string, List> DicMonthDay
{
get { return dicMonthDay; }
set { dicMonthDay = value; }
}
WANIGrid클래스에서 Header 영역을 그리기 위해 호출하는 DrawHeader 메소드의 파라미터를 추가한다.
추가된 파라미터는 고정컬럼을 수정할지/수정을 하지 못하도록 할 것인지를 결정하는 bool 값이다.
고정컬럼이 지정되어져 있을 경우, 고정컬럼에 대한 수정 여부를 넘겨주는 값이다.
public void DrawHeader(Graphics graphics, Rectangle rect, int clientWidth, int colFixed, bool fixedColEditable)
{
if (headerGen != null)
{
if (colFixed < 0) colFixed = 0;
if (colFixed == 0)
{
headerGen.DrawHeaders(firstVisibleCol, lastVisibleCol, clientWidth, graphics, rect);
}
else
{
headerGen.DrawHeaders(colFixed, firstVisibleCol, lastVisibleCol, clientWidth, graphics, rect, fixedColEditable);
}
}
}
지금까지는 새로 추가된 HeaderGenerator인 YearMonthWeekNoDayHeaderGenerator클래스에 대해서 살펴 보았다.
다음에는 이렇게 추가한 Header영역의 클래스를 기반으로 WANIGrid클래스(WANIGrid.cs)에서의 추가/보완 사항들을 하나씩 살펴보기로 하자.