Datagridcolumnstyle avec n'importe quel contrôle: maj (3°)

Description

Cette classe permet de mettre n'importe quel contrôle dans le mode édition de la datagrid et de choisir le type de donnée de la colonne.

La propriété Value ou Text (si Value pas trouvée) de ce contrôle contient automatiquement la valeur de la cellule de la datagrid

Dernière Maj: Correction de la gestion du Null (encore)
- Prise en compte d'une propriété de valeur minimale pour le control de saisi
ex: Le datetimepicker possède une propriété DateMin, si les valeurs sont inférieurs à cette propriété, ca casse. Il suffit d'indiquer le nom de cette propriété dans le constructeurs pour que ca fonctionne (attention à la casse du nom de la propriété)

Source / Exemple :


Public Class DataGridControlColumn
    Inherits System.Windows.Forms.DataGridColumnStyle

#Region "Variables"
    Private _xMargin As Integer = 2
    Private _yMargin As Integer = 1
    Private _Control As System.Windows.Forms.Control
    Private _OldVal As String = String.Empty
    Private _InEdit As Boolean = False
    Public InnerControlType As Type
    Public ColumnDataType As Type
    Public MinimumValuePropertyName As String
#End Region

#Region "Constructeurs"
    Public Sub New(ByVal TypeOfInnerControl As Type, ByVal MappingName As String, ByVal ColumnDataType As Type, ByVal Alignement As System.Windows.Forms.HorizontalAlignment, ByVal HeaderText As String, ByVal NullText As String, ByVal Width As Int32, Optional ByVal MinimumValuePropertyName As String = "")

        MyClass.New(TypeOfInnerControl, MappingName, ColumnDataType, MinimumValuePropertyName)
        MyBase.Alignment = Alignement
        MyBase.HeaderText = HeaderText
        MyBase.MappingName = MappingName
        MyBase.NullText = NullText
        MyBase.Width = Width
    End Sub

    Public Sub New(ByVal TypeOfInnerControl As Type, ByVal MappingName As String, ByVal ColumnDataType As Type, Optional ByVal MinimumValuePropertyName As String = "")

        MyClass.ColumnDataType = ColumnDataType
        MyClass.InnerControlType = TypeOfInnerControl
        MyBase.MappingName = MappingName
        MyClass._Control = Activator.CreateInstance(Me.InnerControlType)
        MyClass._Control.Visible = False
        MyClass.MinimumValuePropertyName = MinimumValuePropertyName

    End Sub

#End Region

    Public Property InnerControl() As System.Windows.Forms.Control
        Get
            Return MyClass._Control
        End Get
        Set(ByVal Value As System.Windows.Forms.Control)
            MyClass._Control = Value
        End Set
    End Property

#Region "Heritage de DataGridColumnStyle"
    Protected Overloads Overrides Sub Abort(ByVal RowNum As Integer)
        MyClass.RollBack()
        MyClass.HideForm()
        MyClass.EndEdit()
    End Sub

    Protected Overloads Overrides Function Commit(ByVal DataSource As System.Windows.Forms.CurrencyManager, ByVal RowNum As Integer) As Boolean
        Try
            MyClass.HideForm()
            If Not MyClass._InEdit Then Return True

            Dim Value As Object
            Dim Prop As Reflection.PropertyInfo = MyClass._Control.GetType.GetProperty("Value")
            If Prop Is Nothing Then
                Value = MyClass._Control.Text
            Else
                Value = Prop.GetValue(MyClass._Control, Nothing)
            End If

            If NullText.Equals(MyClass.GetText(Value)) Then
                Value = System.DBNull.Value
                MyBase.SetColumnValueAtRow(DataSource, RowNum, MyClass.NullText)
            Else
                Value = Convert.ChangeType(Value, MyClass.ColumnDataType)
                If Value.GetType Is MyClass.ColumnDataType Then
                    MyBase.SetColumnValueAtRow(DataSource, RowNum, Value)
                Else
                    Return False
                End If
            End If

        Catch e As Exception
            MyClass.RollBack()
            Return False
        End Try
        MyClass.EndEdit()
        Return True
    End Function

    Protected Overloads Overrides Sub ConcedeFocus()
        MyClass._Control.Visible = False
    End Sub

    Protected Overloads Overrides Sub Edit(ByVal Source As System.Windows.Forms.CurrencyManager, ByVal Rownum As Integer, ByVal Bounds As System.Drawing.Rectangle, ByVal [ReadOnly] As Boolean, ByVal InstantText As String, ByVal CellIsVisible As Boolean)

        If Not InstantText Is Nothing Then
            MyClass._Control.Text = InstantText
        Else            
            MyClass._Control.Text = MyClass.GetText(MyBase.GetColumnValueAtRow(Source, Rownum))
        End If

        Dim OriginalBounds As System.Drawing.Rectangle = Bounds

        MyClass._OldVal = MyClass._Control.Text

        If CellIsVisible Then
            Bounds.Offset(MyClass._xMargin, MyClass._yMargin)
            Bounds.Width -= MyClass._xMargin * 2
            Bounds.Height -= MyClass._yMargin
            MyClass._Control.Bounds = Bounds
            MyClass._Control.Visible = True
        Else
            MyClass._Control.Bounds = OriginalBounds
            MyClass._Control.Visible = False
        End If

        MyClass._Control.RightToLeft = MyBase.DataGridTableStyle.DataGrid.RightToLeft
        MyClass._Control.Focus()

        If MyClass._Control.Visible Then
            MyBase.DataGridTableStyle.DataGrid.Invalidate(OriginalBounds)
        End If

        MyClass._InEdit = True

    End Sub

#Region "Gestion des Tailles"
    Protected Overloads Overrides Function GetMinimumHeight() As Integer
        Return 25  'todo MyClass._Panel.PreferredHeight + MyClass._yMargin
    End Function

    Protected Overloads Overrides Function GetPreferredHeight(ByVal g As System.Drawing.Graphics, ByVal Value As Object) As Integer
        Dim NewLineIndex As Integer = 0
        Dim NewLines As Integer = 0
        Dim ValueString As String = MyClass.GetText(Value)
        Do
            While NewLineIndex <> -1
                NewLineIndex = ValueString.IndexOf("r\n", NewLineIndex + 1)
                NewLines += 1
            End While
        Loop

        Return MyBase.FontHeight * NewLines + MyClass._yMargin
    End Function

    Protected Overloads Overrides Function GetPreferredSize(ByVal g As System.Drawing.Graphics, ByVal Value As Object) As System.Drawing.Size
        Dim Extents As System.Drawing.Size = System.Drawing.Size.Ceiling(g.MeasureString(MyClass.GetText(Value), MyBase.DataGridTableStyle.DataGrid.Font))
        Extents.Width += MyClass._xMargin * 2 + MyClass.DataGridTableGridLineWidth
        Extents.Height += MyClass._yMargin
        Return Extents
    End Function
#End Region

#Region "Méthodes Paint"
    Protected Overloads Overrides Sub Paint(ByVal g As System.Drawing.Graphics, ByVal Bounds As System.Drawing.Rectangle, ByVal Source As System.Windows.Forms.CurrencyManager, ByVal RowNum As Integer)
        MyClass.Paint(g, Bounds, Source, RowNum, False)
    End Sub

    Protected Overloads Overrides Sub Paint(ByVal g As System.Drawing.Graphics, ByVal Bounds As System.Drawing.Rectangle, ByVal Source As System.Windows.Forms.CurrencyManager, ByVal RowNum As Integer, ByVal AlignToRight As Boolean)
        Dim Text As String = MyClass.GetText(MyBase.GetColumnValueAtRow(Source, RowNum))
        MyClass.PaintText(g, Bounds, Text, AlignToRight)
    End Sub

    Protected Overloads Sub Paint(ByVal g As System.Drawing.Graphics, ByVal Bounds As System.Drawing.Rectangle, ByVal Source As System.Windows.Forms.CurrencyManager, ByVal RowNum As Integer, ByVal BackBrush As System.Drawing.Brush, ByVal ForeBrush As System.Drawing.Brush, ByVal AlignToRight As Boolean)

        Dim Text As String = MyClass.GetText(MyBase.GetColumnValueAtRow(Source, RowNum))
        MyClass.PaintText(g, Bounds, Text, BackBrush, ForeBrush, AlignToRight)
    End Sub
#End Region

    Protected Overloads Overrides Sub SetDataGridInColumn(ByVal Value As System.Windows.Forms.DataGrid)
        MyBase.SetDataGridInColumn(Value)
        If Not (MyClass._Control.Parent Is Value) Then
            If Not (MyClass._Control.Parent Is Nothing) Then
                MyClass._Control.Parent.Controls.Remove(MyClass._Control)
            End If
        End If

        If Not (Value Is Nothing) Then
            'MyClass._Control.Owner = Value.FindForm
            Value.Controls.Add(MyClass._Control)
        End If
    End Sub

    Protected Overloads Overrides Sub UpdateUI(ByVal Source As System.Windows.Forms.CurrencyManager, ByVal RowNum As Integer, ByVal InstantText As String)
        MyClass._Control.Text = MyClass.GetText(MyBase.GetColumnValueAtRow(Source, RowNum))
        If Not (InstantText Is Nothing) Then
            MyClass._Control.Text = InstantText
        End If
    End Sub
#End Region

#Region "Méthodes privées"
    Private ReadOnly Property DataGridTableGridLineWidth() As Integer
        Get
            If MyBase.DataGridTableStyle.GridLineStyle = System.Windows.Forms.DataGridLineStyle.Solid Then
                Return 1
            Else
                Return 0
            End If
        End Get
    End Property
    Private Sub EndEdit()
        MyClass._InEdit = False
        MyBase.Invalidate()
    End Sub

    Private Function GetText(ByVal Value As Object) As String

        If MyClass.MinimumValuePropertyName <> String.Empty Then
            Dim Prop As Reflection.PropertyInfo = MyClass._Control.GetType.GetProperty(MyClass.MinimumValuePropertyName)
            If Not Prop Is Nothing Then
                Dim Obj As Object = Convert.ChangeType(Prop.GetValue(MyClass._Control, Nothing), MyClass.ColumnDataType)
                If Value.compareto(Obj) < 0 Then Value = Obj            
            End If
        End If

        If Value Is System.DBNull.Value Then Return NullText

        If Not Value Is Nothing Then
            Return Value.ToString
        Else
            Return NullText
        End If

    End Function

    Private Sub HideForm()
        If MyClass._Control.Focused Then
            MyBase.DataGridTableStyle.DataGrid.Focus()
        End If
        MyClass._Control.Visible = False

    End Sub

    Private Sub RollBack()
        MyClass._Control.Text = MyClass._OldVal
    End Sub

    Private Sub PaintText(ByVal g As System.Drawing.Graphics, ByVal Bounds As System.Drawing.Rectangle, ByVal Text As String, ByVal AlignToRight As Boolean)

        Dim BackBrush As System.Drawing.Brush = New System.Drawing.SolidBrush(MyBase.DataGridTableStyle.BackColor)
        Dim ForeBrush As System.Drawing.Brush = New System.Drawing.SolidBrush(MyBase.DataGridTableStyle.ForeColor)
        MyClass.PaintText(g, Bounds, Text, BackBrush, ForeBrush, AlignToRight)
    End Sub

    Private Sub PaintText(ByVal g As System.Drawing.Graphics, ByVal TextBounds As System.Drawing.Rectangle, ByVal Text As String, ByVal BackBrush As System.Drawing.Brush, ByVal ForeBrush As System.Drawing.Brush, ByVal AlignToRight As Boolean)

        Dim Rect As System.Drawing.Rectangle = TextBounds
        Dim RectF As System.Drawing.RectangleF = System.Drawing.RectangleF.op_Implicit(Rect) ' Convert to RectangleF
        Dim Format As System.Drawing.StringFormat = New System.Drawing.StringFormat()

        If AlignToRight Then Format.FormatFlags = System.Drawing.StringFormatFlags.DirectionRightToLeft

        Select Case Me.Alignment
            Case Is = System.Windows.Forms.HorizontalAlignment.Left
                Format.Alignment = System.Drawing.StringAlignment.Near
            Case Is = System.Windows.Forms.HorizontalAlignment.Right
                Format.Alignment = System.Drawing.StringAlignment.Far
            Case Is = System.Windows.Forms.HorizontalAlignment.Center
                Format.Alignment = System.Drawing.StringAlignment.Center
        End Select

        Format.FormatFlags = Format.FormatFlags Or System.Drawing.StringFormatFlags.NoWrap
        g.FillRectangle(Brush:=BackBrush, Rect:=Rect)

        Rect.Offset(0, MyClass._yMargin)
        Rect.Height -= MyClass._yMargin
        g.DrawString(Text, MyBase.DataGridTableStyle.DataGrid.Font, ForeBrush, RectF, Format)
        Format.Dispose()

    End Sub
#End Region
End Class

Conclusion :


Ce code est basé sur l'exemple de Microsoft (comme le code de strikel).

Code Modifié: Correction de la gestion de la saisie. Ajout de la possibilité de choisir le type de données avec lequel travailler. Passage de valeur par la propriété Text ou Value. Value étant prioritaire, Correction et Amélioration de la gestion des valeurs Null.

Ajout d'un zip contenant un exemple de Datagrid avec TextBox, DataTimePicker et UserControl sur un Databinding avec une collection Typée.

Pas de commentaire pour le moment (pas eu le temps)

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.