반응형

지금까지는 WANIGrid의 겉 모습을 구현해 왔다. 이제는 실제 셀(Cell)의 데이터 입력과 Display 부분을 구현해 보기로 하자. 셀(Cell)의 데이터 입력은 특정 셀(Cell)을 선택하고 한 번 더 클릭을 하면 TextBox가 나타나서 사용자가 입력을 할 수 있도록 되어져 있다.

사용자가 TextBox에 데이터를 입력하면 해당 행(Row)의 선택 컬럼에 입력한 데이터를 저장하고, 저장된 데이터를 화면에 다시 보여주어서 사용자가 확인할 수 있도록 하는 것이다.

이 기능을 구현하기 위해 필요한 각 기능들을 소스를 보면서 확인하도록 하자.

 

하나의 행(Row)에서 원하는 컬럼의 값들을 가져오기 위한 Col Class를 살펴보자.

    /// 1개의 Row에 대한 Column들의 Text값을 가져오기 위한 클래스
    public class Col
    {
        #region 변수
        private List<Header> colHeaders;    //Column의 Header정보를 저장
        private DataRow row;    //Row의 Column정보를 저장하기 위한 DataRow
        private HorizontalAlignment alignment;  //Column의 Text 정렬 방법
        #endregion 변수

        #region Property
        /// Header에 정의된 Column 리스트 설정하거나 반환한다.
        public List<Header> ColHeaders 

        { 

            get { return this.colHeaders; } 

            set { this.colHeaders = value; }

        } 

        /// Column의 정렬방법
        public HorizontalAlignment Alignment
        {
            get { return this.alignment; }
        }

        /// Row의 Column정보를 저장하기 위한 DataRow
        public DataRow Row
        {
            get { return this.row; }
            set { this.row = value; }
        }      
        #endregion Property

        #region 생성자        
        /// 생성자 - 한개의 행에 대한 Column Header정보와 DataRow를 파라미터로 받음
        public Col(List<Header>  headers, DataRow row)
        {
            this.colHeaders = headers;
            this.row = row;
        }

        /// Column ID 값으로 DataRow내의 컬럼 값을 반환
        public string GetColText(string columnId)
        {
            string text = String.Empty;
            if (row[columnId] != null) text = row[columnId].ToString();

            return text;
        }

        /// Column Index에 해당하는 Column 값을 반환
        public string GetColText(int index)
        {
            string text = String.Empty;
            int colNo = 0;
            foreach (Header head in colHeaders)
            {
                if (head.Visible) //Column Header에서 해당 Column을 Visible true일 경우에만 값을 반환 - 화면에 Display하기 위함
                {
                    if (head.Index == index)
                    {
                        text = row[head.ColumnId].ToString();
                        alignment = head.TextAlign;
                    }
                    colNo++;
                }
            }

            return text;
        }
        #endregion 생성자
    }
}

 

처음 Header를 생성할 때 특정 Column을 화면에서 숨기고자 설정할 수도 있다. 이전의 소스 코드에서는 모든 컬럼(Column)의 Visible을 true로 설정하고 개발을 했었다. 하지만 경우에 따라서는 특정 컬럼(Column)이 숨겨져야 할 경우의 처리를 추가하도록 해야 한다.

WANIGrid의 Header영역을 그리는 DrawHeader함수에 컬럼(Column)의 Visible이 true인 경우에만 화면에 나타나도록 처리하는 부분을 추가하도록 한다.

DefaultHeaderGenerator.cs 파일을 열어서 DrawHeaders 메소드에 아래의 부분을 추가한다.

        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;
            graphics.FillRectangle(brush, columnStartX + 1, 1, leftHeaderWidth, topHeaderHeight);
            graphics.DrawRectangle(pen, columnStartX + 1, 1, leftHeaderWidth, topHeaderHeight);
            
            for (int i = firstVisibleCol; i <= lastVisibleCol; i++)
            {                
                if (i == firstVisibleCol) columnStartX += leftHeaderWidth;  //첫 시작컬럼의 폭을 leftHeaderWidth 만큼 설정
                int headerWidth = this._headers[i].Width;   //i 번째 컬럼의 폭을 설정

                if (!this._headers[i].Visible) continue;  //기존 코드에 추가하는 부분

                //보여지는 컬럼의 폭이 컨트롤의 폭 보다 클경우
                if (columnStartX  + headerWidth > controlWidth)
                {
                    headerWidth = controlWidth - columnStartX - 3;
                    if (lastVisibleCol == _headers.Count - 1) IsLargeLastCol = true;
                } else
                {
                    IsLargeLastCol = false;
                }

              :

              :

            }

        }

 

향 후 각 컬럼(Column)에 대한 편집 여부도 설정할 수 있어야 하기에 Header.cs 파일에 boolean 변수와 Property를 추가하도록 한다.

    public abstract class Header
    {
        #region 변수
        private int index;  //Index
        private string columnId;    //컬럼 ID
        private string title;   //컬럼 타이틀
        private int left;   //컬럼 시작위치
        private int width;  //컬럼 폭
        private HorizontalAlignment headAlign;  //컬럼 타이틀 정렬위치
        private HorizontalAlignment textAlign;  //컬럼 내용 정렬위치
        private bool visible = true;    //컬럼 Visible 여부
        private bool editable = true;   //컬럼 편집여부
        #endregion 변수

        :

        public bool Editable
        {
            get { return editable; }
            set { editable = value; }
        }

        :

    }

 

WANIGrid.cs 파일에서 추가 또는 변경되는 부분들을 하나씩 살펴보기로 하자.

마우스로 선택한 특정 셀(Cell)의 컬럼(Column) 중 액티브 컬럼을 설정하기 위한 변수를 선언한다. 사용자가 선택한 Active한 Column 값을 저장하기 위한 변수이다.

private int ActiveCell_ActvieCol = -1;

 

저장된 값을 사용자에게 Display할 때 보여지는 폰드 색상을 검은색으로 설정해서 저장한다. 화면에서 WANIGrid를 그리면서 데이터를 보여줄때 사용할 색상의 Brush이다.

private SolidBrush blackBrush = new SolidBrush(Color.Black);

 

WANIGrid 생성자에 TextBox인 editBox에 설정을 추가한다.

    public WANIGrid()
    {
        InitializeComponent();
        if (grid == null) grid = new WANI_Grid.Grid.Grid();
        rows = new RowCollection();
        hScrollBar.SmallChange = 1;
        rowHeight = Font.Height + 4;
        vScrollBar.SmallChange = rowHeight;
        editBox = new TextBox();
        editBox.BorderStyle = BorderStyle.None;
        editBox.BackColor = Color.White; //배경색을 흰색으로 설정
        editBox.Font = Font;
        editBox.Visible = false;
        Controls.Add(editBox);
        //마우스 우측 버튼 클릭 시 제공되는 ContextMenu 초기화
        InitializeContextMenu();
    }

 

그리고 editBox에 값이 변경되었을 때의 이벤트를 처리할 수 있도록 코드를 추가한다. editBox 값이 변경되면 변경된 값을 행(Row)의 DataRow 변수의 해당 컬럼(Column)에 값을 설정하도록 처리한다.

    public void EventHandlerInitialize()
    {
        //가로 스크롤바
        hScrollBar.Scroll += new ScrollEventHandler(HScrollBar_Scroll);
        //세로 스크롤바
        vScrollBar.Scroll += new ScrollEventHandler(VScrollBar_Scroll);
        //마우스 휠
        this.MouseWheel += new MouseEventHandler(Mouse_Wheel);
        this.editBox.TextChanged += EditBox_TextChanged; //editBox의 TextChanged 이벤트 추가
    }

 

    private void EditBox_TextChanged(object sender, EventArgs e)
    {
        DataRow row = rows[ActiveCell.Row].DataRow;
        Header header = grid.GridHeaderList.Where(x => x.Index == ActiveCell.Col).FirstOrDefault();
        if (header != null)
        {
            if (ActiveCell_ActvieCol > -1) row[header.ColumnId] = editBox.Text;
        }
    }

 

editBox에서 작업시 호출 되는 BeginEdit/EndEdit 메소드를 아래와 같이 수정하도록 한다.

사용자가 특정 셀(Cell)에 값을 입력하기 위한 BeginEdit 메소드가 호출 될 때 TextBox의 좌측과 폭의 값을 조정한다.

    private void BeginEdit()
    {
        if (readOnly) return;

        if (ActiveCell.Col != -1 && ActiveCell.Row != -1)
        {
            string tempStr = "";
            if (rows[ActiveCell.Row].DataRow[grid.GridHeaderList[ActiveCell.Col].ColumnId] != null)
            {
                tempStr = rows[ActiveCell.Row].DataRow[grid.GridHeaderList[ActiveCell.Col].ColumnId].ToString();
            }
            //TextBox에 입력된 값을 설정하고 TextBox 속성의 값을 설정한다.
            editBox.Text = tempStr;
            Rectangle r = GetSelectedCellRect(ActiveCell.Row, ActiveCell.Col);
            editBox.Left = r.Left + 3;
            editBox.Top = r.Top + 3;
            editBox.Height = r.Height;
            editBox.Width = r.Width - 3;
            editBox.Visible = true;
            editBox.Focus();         

            ActiveCell_ActvieCol = ActiveCell.Col;  //ActivieCell_ActiveCol 값을 설정      
        }
    }

 

EndEdit 메소드를 아래와 같이 변경한다.

    private void EndEdit()
    {
        if (readOnly) return;
        if (ActiveCell.Col != -1 && ActiveCell.Row != -1 && editBox.Visible)
        {
            ActiveCell_ActvieCol = -1;
        }
        editBox.Visible = false;
        editBox.Text = "";
        gridState = GridState.ACTIVE;
    }

 

WANIGrid Header 값을 설정할 때 특정 컬럼(Column)을 숨기고자 할 경우 Visible 값이 false인 경우의 컬럼(Column)은 화면에서 보여지지 않아야 한다. 특히 사용자가 WANIGrid 선택 시 마우스 X좌표 값으로 컬럼(Column) 값으로 변환하는 메소드인 GetColFromX에 Header 값을 체크해서 Visible값이 false인 경우에는 처리하지 않는 로직을 추가한다.

    private int GetColFromX(int X)
    {
        int col = 0;
        int tempWidth = leftHeaderWidth;

        if (X >= 0 && X <= leftHeaderWidth)
        {
            col = -1;
        }
        else
        {
            for (col = firstVisibleCol; col < lastVisibleCol; col++)
            {
                if (!grid.GridHeaderList[col].Visible) continue; //Header의 Visible 값이 false인 경우
                int width = grid.GridHeaderList[col].Width;
                if (X < width + tempWidth) break;
                tempWidth += width;
            }
        }
        if (col > grid.GridHeaderList.Count - 1) col = -1;
        return col;
    }

 

마우스 Click시 선택 셀(Cell)을 그리기 위한 Rectangle 값을 반환하는 GetSelectedCellRect 메소드에 Header의 Visible값이 false인 경우를 처리하는 로직을 추가한다.

    protected Rectangle GetSelectedCellRect(int row, int col)
    {
        if (row < firstVisibleRow || row > lastVisibleRow) return new Rectangle(0, 0, 0, 0);
        if (col < firstVisibleCol || col > lastVisibleCol) return new Rectangle(0, 0, 0, 0);

        :

        int left = leftHeaderWidth + 2;
        int width = 0;
        for (int i = firstVisibleCol; i <= lastVisibleCol; i++)
        {
            if (!grid.GridHeaderList[i].Visible) continue;
            :

        }

        return new Rectangle(left - 1, top + 1, width - 1, height - 1);

    }

 

WANIGrid의 최상단 Header영역을 클릭 했을 때 선택된 Column색상을 변환하는 부분에도 Header의 Visible값이 false인 경우 처리하지 않도록 하는 로직을 추가해야 한다.

DrawBackground메소드에서 아래의 파란색 부분을 추가하도록 한다.

    private void DrawBackground(Graphics g, Rectangle rc)
    {
        g.DrawRectangle(new Pen(SystemColors.Control, 2), 0, 0, rc.Width, rc.Height);
        rc.Inflate(-1, -1);
        g.FillRectangle(new SolidBrush(SystemColors.ControlLightLight), rc);

        //선택된 컬럼의 Background를 그린다.
        for (int i = 0; i < selectedCols.Count; i++)
        {
            int index = selectedCols[i];
            int left = leftHeaderWidth;

            for (int j = firstVisibleCol; j < lastVisibleCol && j < index; j++)
            {
                if (!grid.GridHeaderList[j].Visible) continue; //Header의 Visible 체크 
                left += grid.GridHeaderList[j].Width;
            }

            if (allRowsHeight > 0)
            {
                g.FillRectangle(selectedColor, left + 1, topHeaderHeight, grid.GridHeaderList[index].Width + 1, 

                                   allRowsHeight - (rowHeight * firstVisibleRow) + 1);
            }
        }

        :

        :

    }

 

 

 

 

 

 

 

 

반응형

+ Recent posts