现在的位置: 首页 > 综合 > 正文

在DataGrid(Windows Form)中绑定一个日期和时间控件(DatetimePicker)的做法

2013年03月24日 ⁄ 综合 ⁄ 共 6009字 ⁄ 字号 评论关闭
在DataGrid(Windows Form)中绑定一个日期和时间控件(DatetimePicker)的做法

这是项目中用到的一个技术,很多情况下,客户需要大量录入数据,这是为了提高效率,需要在客户端的用户界面上采用DataGrid来处理,但是.NET提供的DataGrid控件的功能有限,一般只能处理文本,当某一列的数据类型是时间和日期型的时候,客户的输入相当麻烦,也不能有效处理用户误输入的错误格式,如果能够将时间日期控件绑定到Grid的单元格中,既加快了用户的录入,也能有效防止用户的错误录入。

进一步,如果我们自定义了一个控件,类似文本框,但是针对特定的应用做过调整,我们也想把它绑定到Grid中,这种情况下也可以采用这里提到的技术。

要想在DataGrid中绑定一个控件,首先需要了解的是在DataGrid中,外观和内容的关系,DataGrid把数据和外观分得很清楚,可以这么认为,DataGrid就是一个空架子,背后有一个非可视化的东西在支持它,这就是DataTableStyle,可以将这个类看作一个集合,是由DataGridColumnStyle组成的,而DataGridColumnStyle本身有外观和数据2个方面的属性,我们绑定一个控件实际上是改变DataGridColumnStyle的外观部分的属性,数据部分的属性等不用管它,这样就能够把需要绑定的控件与DataGridColumnStyle关联起来,进一步就可以和DataTableStyle关联起来,也就可以改变DataGrid的外观了。

因此所有的工作集中在一点上就是完成一个DataGridColumnStyle的改造。所谓的改造也就是从DataGridColumnStyle继承一下。实际上,DataGridTextBoxColumn就是从DataGridColumnStyle继承的。

下面的一个类是将DateTimPicker绑定到DataGridColumnStyle上的一段代码,绑定其它的控件都可以按照这个方法完成。

public class DataGridTimePickerColumn : DataGridColumnStyle
 {
  //这里增加需要被DataGridColumnStyle承载的控件,这里用的是一个
  //DateTimePicker,日期控件,其他的控件类似
  private DateTimePicker myDateTimePicker = new DateTimePicker();
  //isEditing属性用于跟踪用户是否在宿主控件中编辑了其中的数据。
  private bool isEditing;
  
  //构造函数
  public DataGridTimePickerColumn() : base()
  {
   myDateTimePicker.Visible = false;
   myDateTimePicker.Format=DateTimePickerFormat.Time;
   myDateTimePicker.ShowUpDown=true;
  }
  /// <summary>
  /// 此方法必须重载,Abort将启动一个请求来中断编辑过程。
  /// </summary>
  /// <param name="rowNum">当前中断的行号</param>
  protected override void Abort(int rowNum)
  {
   isEditing = false;
   myDateTimePicker.ValueChanged -=new EventHandler(TimePickerValueChanged);
   Invalidate();
  }
  /// <summary>
  /// 此方法必须被重载,而且必须返回2个状态,也就是true或者false,返回false的时候
  /// DataGrid就会用到Abort
  /// </summary>
  /// <param name="dataSource">实际上是一个BindManagerBase</param>
  /// <param name="rowNum">当前提交的行号</param>
  /// <returns></returns>
  protected override bool Commit(CurrencyManager dataSource, int rowNum)
  {
   myDateTimePicker.Bounds = Rectangle.Empty; //表示其属性未被初始化的 Rectangle 结构。
        
   myDateTimePicker.ValueChanged -= new EventHandler(TimePickerValueChanged);

   if (!isEditing)
    return true;

   isEditing = false;

   try
   {
    DateTime dtValue = myDateTimePicker.Value;
    SetColumnValueAtRow(dataSource, rowNum, dtValue);
   }
   catch (Exception)
   {
    Abort(rowNum);
    return false;
   }
   Invalidate();
   return true;
  }
  /// <summary>
  /// 在派生类中被重写时,将准备一个将要进行编辑的单元格。
  /// 通常,Edit 方法将控件定位到网格上要编辑的单元格的位置。
  /// </summary>
  /// <param name="source">DataGridColumnStyle的CurrencyManager,管理 Binding 对象的列表</param>
  /// <param name="rowNum">此列中所编辑的行的行号</param>
  /// <param name="bounds">控件将被放置在其中</param>
  /// <param name="readOnly">指示该列是否为只读的列的值。如果该值是只读,则为 true;否则为 false</param>
  /// <param name="instantText">控件中将显示的文本</param>
  /// <param name="cellIsVisible">指示该单元格是否可见的值。如果该单元格可见,则为 true;否则为 false</param>
  protected override void Edit(
   CurrencyManager source,
   int rowNum,
   Rectangle bounds,
   bool readOnly,
   string instantText,
   bool cellIsVisible)
  {
   DateTime dtValue;

   object obj = GetColumnValueAtRow(source, rowNum);
   if (obj.GetType().ToString()=="System.DateTime")
   {
    dtValue = (DateTime)obj;
   }
   else
   {
    dtValue=DateTime.Now;
   }

   if (cellIsVisible)
   {
    myDateTimePicker.Bounds=new Rectangle(bounds.X+2,bounds.Y+2,bounds.Width-4,bounds.Height-4);
    myDateTimePicker.Value = dtValue;
    myDateTimePicker.Visible = true;
    //挂接一个事件,就是承载的控件的变量发生变化的时候发生的事件
    //在此事件的方法中主要是改变编辑的状态以及调用基类的方法ColumnStartedEditing
    //这个方法用来通知DataGrid开始进入编辑状态
    myDateTimePicker.ValueChanged +=new EventHandler(TimePickerValueChanged);
   }
   else
   {
    myDateTimePicker.Value = dtValue;
    myDateTimePicker.Visible = false;
   }

   if (myDateTimePicker.Visible)
    DataGridTableStyle.DataGrid.Invalidate(bounds);
  }
  protected override Size GetPreferredSize(Graphics g, object value)
  {
   return new Size(100, myDateTimePicker.PreferredHeight + 2);
  }
  protected override int GetMinimumHeight()
  {
   return myDateTimePicker.PreferredHeight + 2;
  }

  protected override int GetPreferredHeight(Graphics g,
   object value)
  {
   return myDateTimePicker.PreferredHeight + 2;
  }
  //重载之一,一个简单的版本,其他没有涉及到的参数采用了默认值  
  protected override void Paint(Graphics g,
   Rectangle bounds,
   CurrencyManager source,
   int rowNum)
  {
   Paint(g, bounds, source, rowNum, false);
  }
  //重载之二,一个简单的版本,其他没有涉及到的参数采用了默认值  
  protected override void Paint(
   Graphics g,
   Rectangle bounds,
   CurrencyManager source,
   int rowNum,
   bool alignToRight)
  {
   Paint(
    g,bounds,
    source,
    rowNum,
    Brushes.Red,
    Brushes.Blue,
    alignToRight);
  }
  /// <summary>
  /// 此方法必须重载,而且,这个方法是一个全面的方法,上面2个方法都是重载的这个方法
  /// 此方法应该是在所承载的控件离开DataGrid之后在DataGrid中写入其中内容的方法
  /// </summary>
  /// <param name="g"></param>
  /// <param name="bounds"></param>
  /// <param name="source"></param>
  /// <param name="rowNum"></param>
  /// <param name="backBrush"></param>
  /// <param name="foreBrush"></param>
  /// <param name="alignToRight"></param>
  protected override void Paint(
   Graphics g,
   Rectangle bounds,
   CurrencyManager source,
   int rowNum,
   Brush backBrush,
   Brush foreBrush,
   bool alignToRight)
  {
   DateTime dtValue;
   object obj = GetColumnValueAtRow(source, rowNum);
   if (obj.GetType().ToString()=="System.DateTime")
   {
    dtValue = (DateTime)obj;
   }
   else
   {
    dtValue=DateTime.Now;
   }

   Rectangle rect = bounds;
   g.FillRectangle(backBrush,rect);
   rect.Offset(0, 2);
   rect.Height -= 2;
   g.DrawString(dtValue.ToString("d"),this.DataGridTableStyle.DataGrid.Font,foreBrush, rect);
  }
  /// <summary>
  /// 将要承载的控件关联到DataGrid上
  /// </summary>
  /// <param name="dgValue"></param>
  protected override void SetDataGridInColumn(DataGrid dgValue)
  {
   base.SetDataGridInColumn(dgValue);
   if (myDateTimePicker.Parent != null)
   {
    myDateTimePicker.Parent.Controls.Remove(myDateTimePicker);
   }
   if (dgValue != null)
   {
    dgValue.Controls.Add(myDateTimePicker);
   }
  }
  /// <summary>
  /// 被承载的控件的内容发生变化的时候表明用户进行了编辑,此时执行这个事件处理函数
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void TimePickerValueChanged(object sender, EventArgs e)
  {
   this.isEditing = true;
   //通知DataGrid已经开始编辑这一列,其中的参数是需要承载的控件
   base.ColumnStartedEditing(myDateTimePicker);
  }
 }

抱歉!评论已关闭.