본문 바로가기

IT/Component

[Devexpress] Grid 의 CheckEdit 컬럼의 헤더에 전체선택(해제)기능 넣기

== 여기에서 체크박스가 표시되는 Column 의 FieldName 은 "Select"로 함 ==

 

1. 다음을 전역변수로 선언

  
  /// 
  /// CheckBox 로 표시될 ColumnEdit
  /// 
  RepositoryItemCheckEdit _repChkYN = new RepositoryItemCheckEdit();
  /// 
  /// 전체선택 체크박스 상태
  /// 
  private bool _stateAllSel = false;

 

2. ColumnEdit 기본설정 및 체크박스를 표시할 컬럼에 ColumnEdit 를 지정

  
   _repChkYN.ValueChecked = "Y";
   _repChkYN.ValueUnchecked = "N"
   _repChkYN.ValueGrayed = "";
  colSel.ColumnEdit = _repChkYN;
 

 

3. ColumnEdit 및 GridVIew 에 다음 이벤트 추가


  
  _repChkYN.EditValueChanged += _repChkYN_EditValueChanged;

/// 
/// 선택 CheckEdit 변경
/// 
/// 
/// 
void _repChkYN_EditValueChanged(object sender, EventArgs e)
{
DataRow dr = gvMain.GetFocusedDataRow();
dr["Select"] = gvMain.EditingValue;
dr.EndEdit();
_stateAllSel = IsAllSelected();
gvMain.LayoutChanged();
}
  /// 
  /// 선택컬럼이 모두 선택되어있는지 여부를 리턴
  /// 
  /// 
  bool IsAllSelected()
  {
   if(GridData != null)
   {
    foreach(DataRow dr in GridData.Rows)
    {
     if(dr["Select"].GMSToString() == "N")
     {
      return false;
     }
    }
    return true;
   }
   return false;
  }

   this.gvMain.CustomDrawColumnHeader += gvMain_CustomDrawColumnHeader;

  /// 
  /// 컬럼헤더 CustomDraw
  /// 
  /// 
  /// 
  void gvMain_CustomDrawColumnHeader(object sender, ColumnHeaderCustomDrawEventArgs e)
  {
   if(e.Column != colSel)
   {
    return;
   }
   Rectangle rect = e.Bounds;
   e.Appearance.FillRectangle(e.Cache, rect);
   e.Info.Caption = "";
   e.Painter.DrawObject(e.Info);
   TextOptions to = e.Appearance.TextOptions;
   to.HAlignment = HorzAlignment.Center;
   int textHeight = Math.Round(DevExpress.Utils.Paint.XPaint.Graphics.CalcTextSize(e.Graphics, "선택", e.Appearance.Font, e.Appearance.GetStringFormat(to), colSel.Width).Height).CPJToInt();
   DevExpress.Utils.Paint.XPaint.Graphics.DrawString(e.Cache, "선택", e.Appearance.Font, e.Appearance.GetTextureBrush()
    , new Rectangle(e.Bounds.X, (e.Bounds.Height / 2) - textHeight, e.Bounds.Width, textHeight), e.Appearance.GetStringFormat(to));
   Size size = CheckBoxRenderer.GetGlyphSize(e.Graphics, CheckBoxState.UncheckedNormal);
   Rectangle rectCheck = new Rectangle((rect.Width - size.Width) / 2, (rect.Height - size.Height) / 2 + textHeight, size.Width, size.Height);
   DrawCheckBox(e.Graphics, rectCheck);
   e.Handled = true;
  }

  /// 
  /// 현재테마와 동일하게 체크박스를 그려줌
  /// 
  /// 
  /// 
  void DrawCheckBox(Graphics g, Rectangle r)
  {
   DevExpress.XtraEditors.ViewInfo.CheckEditViewInfo info = default(DevExpress.XtraEditors.ViewInfo.CheckEditViewInfo);
   DevExpress.XtraEditors.Drawing.CheckEditPainter painter = default(DevExpress.XtraEditors.Drawing.CheckEditPainter);
   DevExpress.XtraEditors.Drawing.ControlGraphicsInfoArgs args = default(DevExpress.XtraEditors.Drawing.ControlGraphicsInfoArgs);
   info = (CheckEditViewInfo)_repChkYN.CreateViewInfo();
   painter = (CheckEditPainter)_repChkYN.CreatePainter();
   info.EditValue = _stateAllSel ? "Y" : "N";
   info.Bounds = r;
   info.CalcViewInfo(g);
   args = new DevExpress.XtraEditors.Drawing.ControlGraphicsInfoArgs(info, new DevExpress.Utils.Drawing.GraphicsCache(g), r);
   painter.Draw(args);
   args.Cache.Dispose();
  }
   this.gvMain.MouseUp += gvMain_MouseUp;

  /// 
  /// Grid Click 이벤트
  /// 
  /// 
  /// 
  private void gvMain_MouseUp(object sender, MouseEventArgs e)
  {
   if(e.Button == MouseButtons.Left && e.Clicks == 1)
   {
    GridView view = (GridView)sender;
    GridHitInfo hInfo = view.CalcHitInfo(e.Location);
    if(hInfo.HitTest == GridHitTest.Column && hInfo.Column == colSel)
    {
     _stateAllSel = !_stateAllSel;
     for(int k = 0 ; k < gvMain.DataRowCount ; k++)
     {
      gvMain.SetRowCellValue(k, "Select", _stateAllSel ? "Y" : "N");
     }
    }
   }
  }
 

============ 스크린샷 ============

 

 

============ 요약 ============

- Row 의 Data 는 "Y", "N" 으로 true, false 를 구분함.

- 컬럼헤더의 CheckBox 는 Custom Draw 하되 Caption 다음에 한줄 띄워서 CheckBox 를 표시하고, 중앙정렬

- 컬럼헤더의 CheckBox 를 클릭하는 경우 모든행의 체크상태가 한번에 변경이 되고,

  데이터 행의 체크값을 변경시 컬럼헤더의 체크상태는 모든행의 데이터가 체크표시된 경우만 체크되게 동작함.

  그래서 데이터행의 체크상태가 변경되는 시점에 컬럼헤더의 체크박스도 다시 그려줘야함...

 

==== 고민한 부분 ====

데이터행의 체크상태가 변경되는 시점에 컬럼헤더의 체크박스도 다시 그려줘야함...

위 부분에서 행이 바뀌지 않는한 DataSource 변경이벤트(ValueChanged) 가 발생되지 않아서, 행을 변경해야 컬럼헤더의 체크상태가 반영이됨.

 

이 문제를 해결하기 위해 RepositoryItemCheckEdit 의 EditValueChanged 이벤트에서

 

- DataSource 의 값을 바로 변경시켜주고,

DataRow dr = gvMain.GetFocusedDataRow();
dr["Select"] = gvMain.EditingValue;
dr.EndEdit();

 

- 전체선택여부 전역변수를 갱신한 다음

_stateAllSel = IsAllSelected();

 

- gvMain.LayoutChanged(); 를 호출해줘야

GridView 의 CustomDrawColumnHeader 이벤트가 발생이 되면서 컬럼헤더의 체크상태가 업데이트됨.

(gvMain.LayoutChanged(); 를 호출하지 않고, Grid 의 ValueChanged 이벤트만 호출해봐야 실제 UI 에 반영이 안됨. gvMain.LayoutChanged(); 를 찾는데 애먹었음)