顯示具有 DateGridView 標籤的文章。 顯示所有文章
顯示具有 DateGridView 標籤的文章。 顯示所有文章

2018/01/11

[C#] DateGridView 使用 ComboBox 與 DateTimePicker

這一篇主要是針對 https://nonfu.blogspot.tw/2017/12/c-dategridview-datetimepicker.html 所併發出來的想法與程式碼改進 主要就是讓 DataGridView 能使用 DateTimePicker 與 ComboBox 並改進不足之處。

最終完成的成果如下方的圖

程式碼如下:

public partial class DataGridViewEx:System.Windows.Forms.DataGridView
{
 private Point MyPoint;
 private Control parentCTL;
 private ComboBox dtCombo;
 private DateTimePicker dtPicker;

 /// 紀錄可編輯的欄位名稱
 private StringDictionary ColmmEdit;

 /// 紀錄要使用日期資料的欄位名稱
 private StringDictionary ColmmDate;

 /// 紀錄要使用的下拉欄位名稱
 private StringDictionary ColmmCombo;

 public DataGridViewEx() : base()
 {
  this.EditMode = DataGridViewEditMode.EditProgrammatically;
  if (!DesignMode)
  {
   MyPoint = new Point();
   ColmmEdit = new StringDictionary();
   ColmmDate = new StringDictionary();
   ColmmCombo = new StringDictionary();

   this.Disposed += DataGridViewEx_Disposed;
   this.CellClick += DataGridViewEx_CellClick;
   this.CellEnter += DataGridViewEx_CellClick;
   this.EditingControlShowing += DataGridViewEx_EditingControlShowing;

   FirstSetDataTimePicker();
   FirstSetComboBox();

   this.AllowUserToAddRows = true;
   this.AllowUserToDeleteRows = true;
   this.AllowUserToOrderColumns = false;
   this.AllowUserToResizeColumns = false;
   this.AllowUserToResizeRows = false;
  }
 }

 private void DataGridViewEx_Disposed(object sender, EventArgs e)
 {
  if (!DesignMode)
  {
   dtPicker.Dispose();
   dtCombo.Dispose();
  }
 }
       
 /// 設定可編輯的欄位
 public void SetColmmEditName(string NameValue)
 {
  if(!ColmmEdit.ContainsKey(NameValue))
  {
   ColmmEdit.Add(NameValue, NameValue); 
  }
 }

 /// 設定要使用DateTimePicker的欄位
 public void SetColmmDateName(string NameValue)
 {
  if (!ColmmDate.ContainsKey(NameValue))
  {
   ColmmDate.Add(NameValue, NameValue);
  }
 }

 /// 設定要使用ComboBox的欄位
 public void SetColmmComboName(string NameValue)
 {
  if (!ColmmCombo. ContainsKey(NameValue))
  {
   ColmmCombo.Add(NameValue, NameValue);
  }
 }

 /// 檢查欄位是否可以編輯
 private void DataGridViewEx_CellClick(object sender, DataGridViewCellEventArgs e)
 {
  if(this.Rows.Count>0)
  {
   if ((e.RowIndex> -1) && (e.ColumnIndex > -1))
   {
     if (ColmmEdit.ContainsKey(this.Columns[e.ColumnIndex].Name))
     {
      this.BeginEdit(true);
     }
     else
     {
      this.EndEdit();
     }
    }
    else
    {
     this.EndEdit();
    }
   }
  }

 /// 判斷是否使用DateTimePicker、ComboBox
 private void DataGridViewEx_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
 {
  if (this.Rows.Count > 0)
  {
   if (this.CurrentCell.RowIndex > -1 && this.CurrentCell.ColumnIndex > -1)
   {
    if (parentCTL == null)
    {
     parentCTL = e.Control.Parent;
     parentCTL.Controls.Add(dtPicker);
     parentCTL.Controls.Add(dtCombo);
    }
    MyPoint.X = e.Control.Location.X - e.Control.Margin.Left < 0 ? 0 : e.Control.Location.X - e.Control.Margin.Left;
    MyPoint.Y = e.Control.Location.Y - e.Control.Margin.Top < 0 ? 0 : e.Control.Location.Y - e.Control.Margin.Top;
                    
    if (ColmmDate.ContainsKey(this.Columns[this.CurrentCell.ColumnIndex].Name))
    {
     SetDataTimePickerView(ref e);
    }
    else
    {
     MyPoint.X = 0;
     MyPoint.Y = 0;
     dtPicker.Location = MyPoint;
     dtPicker.Visible = false;
    }

    if (ColmmCombo.ContainsKey(this.Columns[this.CurrentCell.ColumnIndex].Name))
    {
     SetComboBoxView(ref e);
    }
    else
    {
     MyPoint.X = 0;
     MyPoint.Y = 0;
     dtCombo.Location = MyPoint;
     dtCombo.Visible = false;
    }
   }
  }
 }

 private void FirstSetComboBox()
 {
  dtCombo = new ComboBox();
  dtCombo.Name = "ComboBox1";
  dtCombo.FlatStyle = FlatStyle.Flat;

  dtCombo.Font = this.AlternatingRowsDefaultCellStyle.Font;
  dtCombo.Visible = false;
  dtCombo.SelectedIndexChanged += new EventHandler(ComboBox1_SelectedIndexChanged);
 }

 private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
 {
  this.CurrentCell.Value = ((ComboBox)sender).SelectedItem;
 }

 /// 設定下拉選單內容
 public void SetComboData(string[] Value)
 {
  dtCombo.Items.Clear();
  dtCombo.Items.AddRange(Value);
 }

 private void SetComboBoxView(ref DataGridViewEditingControlShowingEventArgs e)
 {
  dtCombo.Size = this.CurrentCell.Size;
  dtCombo.Location = MyPoint;
  if (e.Control.Text != "")
  {
   dtCombo.SelectedItem = e.Control.Text;
  }
  else
  {
   dtCombo.SelectedIndex = -1;
  }          
  
  e.Control.Visible = false;
  dtCombo.Visible = true;
 }

 /// DateTimePicker的日期資料回寫欄位
 private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
 {
   this.CurrentCell.Value = ((DateTimePicker)sender).Value.ToString("yyyy/MM/dd");
 }

 private void FirstSetDataTimePicker()
 {
  dtPicker = new DateTimePicker();
  dtPicker.Name = "dateTimePicker1";
  dtPicker.Format = DateTimePickerFormat.Custom;
  dtPicker.CustomFormat = "yyyy/MM/dd";
  dtPicker.MinDate = DateTime.Parse("1920/01/01");
  dtPicker.CalendarFont = this.AlternatingRowsDefaultCellStyle.Font;
  dtPicker.Visible = false;
  dtPicker.ValueChanged += new EventHandler(dateTimePicker1_ValueChanged);
 }

 private void SetDataTimePickerView(ref DataGridViewEditingControlShowingEventArgs e)
 {
  dtPicker.Size = this.CurrentCell.Size;
  dtPicker.Location = MyPoint;
  dtPicker.MaxDate = DateTime.Now;
  if (e.Control.Text != "")
  {
   dtPicker.Value = DateTime.ParseExact(e.Control.Text, dtPicker.CustomFormat, null);
  }
  else
  {
   dtPicker.Value = DateTime.Now;
   this.CurrentCell.Value = dtPicker.Value.ToString("yyyy/MM/dd");
  }
  
   e.Control.Visible = false;
   dtPicker.Visible = true;
 }

}

2017/12/17

[C#] DateGridView 使用 DateTimePicker 輸入日期

使用DateGridView常常遇到需要輸入日期的情境,對使用者來說DateTimePicker是很直覺的輸入方式
但是原始的DateGridView並不支援DateTimePicker的使用,以往為了解決這個問題,我都是參考微軟
的這一篇 https://msdn.microsoft.com/zh-tw/library/7tas5c80.aspx 進行修改
最近看到這一篇 https://dotblogs.com.tw/danking/2014/11/13/147294 讓我興起改寫
DateGridView的想法。

對於改寫控制項還不是很了解要如何使用在專案的人,可以參考我的另一篇文https://nonfu.blogspot.tw/2017/11/c-checkbox.html

public partial class DataGridViewEx:System.Windows.Forms.DataGridView
{
  // 紀錄可編輯的欄位名稱
  private StringDictionary ColmmEdit;

  // 紀錄要使用日期資料的欄位名稱
  private StringDictionary ColmmDate;

  public DataGridViewEx() : base()
  {
    this.EditMode = DataGridViewEditMode.EditProgrammatically;
    if (!DesignMode)
    {
      ColmmEdit = new StringDictionary();
      ColmmDate = new StringDictionary();
      this.Disposed += DataGridViewEx_Disposed;
      this.CellClick += DataGridViewEx_CellClick;
      this.EditingControlShowing += DataGridViewEx_EditingControlShowing;          
     }
  }

  // 刪除資料清單
  private void DataGridViewEx_Disposed(object sender, EventArgs e)
  {
    if (!DesignMode)
    {
      ColmmEdit.Clear();
      ColmmDate.Clear();
    }
  }
       
  // 設定可編輯的欄位
  public void SetColmmEditName(string NameValue)
  {
    if(!ColmmEdit.ContainsKey(NameValue))
    {
      ColmmEdit.Add(NameValue, NameValue); 
    }
  }

  // 設定要使用DateTimePicker的欄位
  public void SetColmmDateName(string NameValue)
  {
    if (!ColmmDate.ContainsKey(NameValue))
    {
      ColmmDate.Add(NameValue, NameValue);
    }
  }

  // 檢查欄位是否可以編輯
  private void DataGridViewEx_CellClick(object sender, DataGridViewCellEventArgs e)
  {
    if ((e.RowIndex > -1) || (e.ColumnIndex > -1))
    {

      if (ColmmEdit.ContainsKey(this.Columns[e.ColumnIndex].Name))
      {
        this.BeginEdit(true);
      }
      else
      {
        this.EndEdit();
      }

    }
  }

  // DateTimePicker的日期資料回寫欄位
  private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
  {
    this .CurrentCell.Value = ((DateTimePicker)sender).Value.ToString("yyyy/MM/dd");
  }

  // 判斷是否適用DateTimePicker的欄位
  private void DataGridViewEx_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
  {
    if (this.CurrentCell.ColumnIndex > -1)
    {
      Control parentCTL = e.Control.Parent;

      if(ColmmDate.ContainsKey(this.Columns[this.CurrentCell.ColumnIndex].Name))
      {
        DateTimePicker dtPicker = new DateTimePicker();
        dtPicker.Name = "dateTimePicker1";
        dtPicker.Size = this .CurrentCell.Size;
        dtPicker.Format = DateTimePickerFormat.Custom;
        dtPicker.CustomFormat = "yyyy/MM/dd";

        dtPicker.Location = new Point(
                                      e.Control.Location.X - e.Control.Margin.Left < 0 ? 0 : e.Control.Location.X - e.Control.Margin.Left,
                                      e.Control.Location.Y - e.Control.Margin.Top < 0 ? 0 : e.Control.Location.Y - e.Control.Margin.Top);

        if (e.Control.Text != "")
        {
          dtPicker.Value = DateTime.ParseExact(e.Control.Text, dtPicker.CustomFormat, null);
        }
        else
        {
          dtPicker.Value = DateTime.Now;
          this.CurrentCell.Value = dtPicker.Value.ToString("yyyy/MM/dd");
        }

        e.Control.Visible = false;

        foreach (Control tmpCTL in parentCTL.Controls)
        {
          if (tmpCTL.Name == dtPicker.Name) parentCTL.Controls.Remove(tmpCTL);
        }

        parentCTL.Controls.Add(dtPicker);
        dtPicker.ValueChanged += new EventHandler(dateTimePicker1_ValueChanged);              
      }
      else
      {
        foreach (Control tmpCTL in parentCTL.Controls)
        {
          if (tmpCTL.Name == "dateTimePicker1")
          {
           parentCTL.Controls.Remove(tmpCTL);
          }
        }
      }
    }
  }
}