在DataGrid里内嵌控件

来源:互联网 发布:全国网络教育排名 编辑:程序博客网 时间:2024/05/29 17:50
DataGrid里内嵌控件
 
在单元格里面内嵌控件,是一个迷人的功能。但是要用好这一招可并不像想象中那么容易。互联网上关于在DataGrid里面内嵌ComboBox的文章能把人看晕了。但是效果却不怎么理想。所以我认为要用好内嵌控件这招必须从根子上入手。DataGridColumnStyle这个类可能并不是非常引人注目,但是它的两个派生类我想大家都是非常熟悉的,那就是DataGridTextBoxColumnDataGridBoolColumn类。这两个类的用法不在这里重复。现在要强调的是他们的父类DataGridColumnStyle。它是一个抽象类。而我们可以从该类派生出像DataGridTextBoxColumnDataGridBoolColumn那样的子类,也就是说,你可以让单元格在被单击的时候变成一个ComboBox或者DateTimePicker,或者任何你想要的东西。你只需要从DataGridColumnStyle派生出一个自己的类就可以了。但是DataGridColumnStyle这只小狗有点复杂,所以必须仔细研究一下。根据功能不同,该类提供了三组需要重写的方法:
 
把自己画出来的方法:
 
ConcedeFocus——通知列必须放弃它承载的控件的焦点。
GetMinimumHeight——将获取一行的最小高度。
GetPreferredHeight——获取自动调整列的大小所用的高度。
GetPreferredSize——获取自动调整烈的大小所用的size
Paint(三个)——在DataGrid上面画出自己。一般都是先画出背景,然后画字。最后一个Paint方法的参数多达7个。就在这个参数最多的方法里画出单元格的背景和文本。其它两个Paint方法逐次调用,最后调用到参数最多的Paint方法。
SetDataGridInColumn——把内嵌控件添加到DataGrid里。这个方法非常重要,如果遗漏或者处理不当,很有可能显示不出内嵌控件,或者出现其它意想不到的事情。
 
在格与内嵌控件之间的转换,以及利用内嵌控件编辑值的方法:
 
Abort——启动一个请求来中断编辑过程。在这个方法需要首先把正在编辑的标志设置为否,然后写在ValueChanged事件的句柄,最后调用Invalidate方法重绘。
Commit——提交。首先写在内嵌控件的ValueChanged事件句柄,然后把内嵌控件的值传递给单元格,隐藏内嵌控件,最后调用Invalidate()方法重绘单元格。
Edit——编辑。首先必须判断该列是否是只读的,然后从单元格里得到值,在交给内嵌控件,给内嵌控件设置显示区域及外观,最后让内嵌控件可见并且得到焦点。
EnterNullValue——输入空值。
 
于这些方法相关的有一个非常重要的标志isEditing。该标志表示单元格里的值是否增在被编辑。一般,需要将其声明成私有或保护的布尔变量。
 
原则:由于SetColumnValueAtRow方法的Value参数是Object类型,而且GetColumnValueAtRow方法的返回值同样也是Object类型的。所以,在Commit方法里应该把从内嵌控件接收到的值转换成Object类型,然后送给SetColumnValueAtRow方法。而在Edit方法中,内嵌控件接收什么类型的值就把从单元格接收来的值转换成什么类型,然后传递给内嵌控件。
 
在格与内嵌控件之间传递值的方法:
 
GetColumnValueAtRow——从一个单元格把值取出来,然后作为返回值返回。
SetColumnValueAtRow——把内嵌控件的值传递回单元格。
 
需要注意的是,处理DBNull的策略,最好就在这两个方法里决定。
 
除此之外,还必须对只读策略做出明智的决策。为此,添加IsReadOnly方法,该方法返回true,只读,否则,不只读。
 
在制作内嵌控件类的时候应遵循以下步骤:
 
DataGridColumnStyle类继承;
完成负责在Cell与内嵌控件之间传递值的方法,并去订DBNull的处理方式;
完成IsReadOnly方法,确定只读策略;
完成把自己画出来的方法;
完成单元格与内嵌控件转换,以及利用内嵌控件编辑值的方法。
 
 
实例制作
 
DataGridDateTimePickerColumn类的功能描述
 
该类从DataGridColumnStyle派生
设计用户控件的时候一定要注意一点,用户控件的用户是两种人,一是使用这个控件编程的程序员,一是使用程序的最终用户。所以要分别从这两种人的角度出发描述他们对控件的要求。
 
设计时:
程序员可以通过编程的方式把它安置在数据网格里
         需要在数据网格里面做一些安排。做一个能够直接把它添加进数据网格的方法。
程序员可以通过编程的方式指定它是否是只读的
         通过一个属性ReadOnly和方法IsReadOnly解决这个问题。属性ReadOnly标志该列是否为只读。方法IsReadOnly决定只读策略。现在的策略就是,该列是否为只读只取决于ReadOnly本身,而与数据网格是否只度无关。
程序员可以通过编程的方式指定日期显示的格式
         日期时间一起显示、只显示日期、只显示时间
         通过属性Format设置
程序员可以通过编程的方式指定DateTimePicker里是否显示UpDown按钮
         属性ShowUpDown
程序员可以通过编程的方式指定映射到数据表的哪一列
         通过MappingName属性实现这个功能
程序员可以通过编程的方式指定列头的文本
         通过HeaderText属性实现这个功能
程序员可以通过编程的方式设置对齐方式
         属性Alignment;方法Paint()里也要相应做出处理
程序员可以通过编程方式设置当值为null时显示的文本
         属性NullText;方法Paint()里也要作出相应处理
程序员可以通过编程方式设置宽度
         属性Width
程序员可以轻松扩展它的功能
         所有的属性和方法都是protected overridable
 
运行时:(描述)
当用户使数据网格显示出来的时候,DataGridDateTimePickerColumn也被显示出来。它应该有两种显示形式:普通CellDateTimePicker。初始的时候就是Cell形式,时间值以文本的形式显示在单元格里。而picker这时是隐藏的,不显示出来的。当单元格被单击的时候,单元格里面就会显示出一个DateTimePicker控件。DateTimePicker的值和单元格相等。这就需要把单元格里面的值传递给pickerpicker外观的颜色应和数据网格保持一致。用户可以使用它编辑值。就跟使用DataTimePicker控件一样。当另一个单元格被单击的时候,DateTimePicker消失。被编辑过后的新值重新以单元格的形式显示出来。当然这时需要把picker的值传递回单元格。应该有一个比较理想的运行效率。可以显示null值。用户可以输入null值。
 
程序参考:
 
' This example shows how to create your own column style that
' hosts a control, in this case, a DateTimePicker.
Public Class DataGridTimePickerColumn
    Inherits DataGridColumnStyle
 
    Private customDateTimePicker1 As New CustomDateTimePicker()
 
    ' The isEditing field tracks whether or not the user is
    ' editing data with the hosted control.
    Private isEditing As Boolean
 
    Public Sub New()
        customDateTimePicker1.Visible = False
    End Sub
 
    Protected Overrides Sub Abort(ByVal rowNum As Integer)
        isEditing = False
        RemoveHandler customDateTimePicker1.ValueChanged, _
            AddressOf TimePickerValueChanged
        Invalidate()
    End Sub
 
    Protected Overrides Function Commit _
        (ByVal dataSource As CurrencyManager, ByVal rowNum As Integer) _
        As Boolean
 
        customDateTimePicker1.Bounds = Rectangle.Empty
 
        RemoveHandler customDateTimePicker1.ValueChanged, _
            AddressOf TimePickerValueChanged
 
        If Not isEditing Then
            Return True
        End If
        isEditing = False
 
        Try
            Dim value As DateTime = customDateTimePicker1.Value
            SetColumnValueAtRow(dataSource, rowNum, value)
        Catch
        End Try
 
        Invalidate()
        Return True
    End Function
 
    Protected Overloads Overrides Sub Edit( _
        ByVal [source] As CurrencyManager, _
        ByVal rowNum As Integer, _
        ByVal bounds As Rectangle, _
        ByVal [readOnly] As Boolean, _
        ByVal displayText As String, _
        ByVal cellIsVisible As Boolean)
 
        Dim value As DateTime = _
        CType(GetColumnValueAtRow([source], rowNum), DateTime)
        If cellIsVisible Then
            customDateTimePicker1.Bounds = New Rectangle _
            (bounds.X + 2, bounds.Y + 2, bounds.Width - 4, _
            bounds.Height - 4)
 
            customDateTimePicker1.Value = value
            customDateTimePicker1.Visible = True
            AddHandler customDateTimePicker1.ValueChanged, _
            AddressOf TimePickerValueChanged
        Else
            customDateTimePicker1.Value = value
            customDateTimePicker1.Visible = False
        End If
 
        If customDateTimePicker1.Visible Then
            DataGridTableStyle.DataGrid.Invalidate(bounds)
        End If
 
        customDateTimePicker1.Focus()
 
    End Sub
 
    Protected Overrides Function GetPreferredSize( _
        ByVal g As Graphics, _
        ByVal value As Object) As Size
 
        Return New Size(100, customDateTimePicker1.PreferredHeight + 4)
 
    End Function
 
    Protected Overrides Function GetMinimumHeight() As Integer
        Return customDateTimePicker1.PreferredHeight + 4
    End Function
 
    Protected Overrides Function GetPreferredHeight( _
        ByVal g As Graphics, ByVal value As Object) As Integer
 
        Return customDateTimePicker1.PreferredHeight + 4
 
    End Function
 
    Protected Overloads Overrides Sub Paint( _
        ByVal g As Graphics, ByVal bounds As Rectangle, _
        ByVal [source] As CurrencyManager, ByVal rowNum As Integer)
 
        Paint(g, bounds, [source], rowNum, False)
 
    End Sub
 
    Protected Overloads Overrides Sub Paint(ByVal g As Graphics, _
        ByVal bounds As Rectangle, ByVal [source] As CurrencyManager, _
        ByVal rowNum As Integer, ByVal alignToRight As Boolean)
 
        Paint(g, bounds, [source], rowNum, Brushes.Red, _
            Brushes.Blue, alignToRight)
 
   End Sub
 
    Protected Overloads Overrides Sub Paint(ByVal g As Graphics, _
        ByVal bounds As Rectangle, ByVal [source] As CurrencyManager, _
        ByVal rowNum As Integer, ByVal backBrush As Brush, _
        ByVal foreBrush As Brush, ByVal alignToRight As Boolean)
 
        Dim [date] As DateTime = _
        CType(GetColumnValueAtRow([source], rowNum), DateTime)
        Dim rect As Rectangle = bounds
        g.FillRectangle(backBrush, rect)
        rect.Offset(0, 2)
        rect.Height -= 2
        g.DrawString([date].ToString("d"), _
            Me.DataGridTableStyle.DataGrid.Font, foreBrush, _
            RectangleF.FromLTRB(rect.X, rect.Y, rect.Right, rect.Bottom))
 
    End Sub
 
    Protected Overrides Sub SetDataGridInColumn(ByVal value As DataGrid)
        MyBase.SetDataGridInColumn(value)
        If Not (customDateTimePicker1.Parent Is Nothing) Then
            customDateTimePicker1.Parent.Controls.Remove(customDateTimePicker1)
        End If
        If Not (value Is Nothing) Then
            value.Controls.Add(customDateTimePicker1)
        End If
    End Sub
 
    Private Sub TimePickerValueChanged( _
        ByVal sender As Object, ByVal e As EventArgs)
 
        ' Remove the handler to prevent it from being called twice in a row.
        RemoveHandler customDateTimePicker1.ValueChanged, _
            AddressOf TimePickerValueChanged
        Me.isEditing = True
        MyBase.ColumnStartedEditing(customDateTimePicker1)
 
    End Sub
 
End Class
 
Public Class CustomDateTimePicker
    Inherits DateTimePicker
 
    Protected Overrides Function ProcessKeyMessage(ByRef m As Message) As Boolean
        ' Keep all the keys for the DateTimePicker.
        Return ProcessKeyEventArgs(m)
    End Function
 
End Class
 
原创粉丝点击