none
[VS2005] Problem mit DGV und Eingabeverhalten einer CB-Cell RRS feed

  • Frage

  • Hi Leute,

    noch etwas neu in .Net und auch noch recht unerfahren mit dem
    Überschreiben vorgegebener Komponenten, suche ich nach guten Quellen,
    die mir helfen können das gezielte Überschreiben von Basiskomponenten
    und deren Funktionsweisen zu lernen.

    Bei Recherchen im Netz bin ich auf unterschiedliche kommerzielle
    Angebote gestoßen (aka Fertiglösungen), die ich aber vorweg erstmal
    ausschließen möchte. Mein Ziel ist es das selbst zu tun und daran auch
    zu lernen. So schwierig kann das im Einzelfall ja nicht sein.

    Ein erster Versuch mit Hilfe einer Quelle im Web ist zum Glück
    gelungen. Speziell geht es bei meinem zweiten Versuch darum, einer
    ComboBoxCell eines DGV abzugewöhnen, nur Listform zu sein, sondern
    auch Eingabefeld (DropDownStyle=DropDown). Das ist mir sogar gelungen.
    Dummerweise geht danach nur nix. Die Eingabe geht bei Return verloren,
    es findet keine Übernahme in die Zelle statt und der Focus geht in die
    nächste Zeile anstatt sinnigerweise in das nächste freie Feld der
    selben Zeile. Ich verstehe auch zugegebenermaßen die innere
    Architektur dieses DGV nicht ganz. Vielleicht kann mir da ja ein
    erfahrener Komponentencoder mal auf die Sprünge helfen. (Bei zu
    umfangreichen und für die ganze Gruppe nicht mehr interessanten oder
    zu banalen Beschreibungen auch gerne per direkter PN.)

    Quellcodes, die ich mit Google gesucht haben, haben mir bisher zu
    diesem Thema nichts gebracht. Teils waren sie veraltet (VB6), teils
    waren sie schlicht falsch und funktionierten nicht, teils waren sie so
    schlecht kommentiert, dass ich Wochen bräuchte mich da hineinzulesen.

    Vielleicht kann mir einer von euch da helfen.

    LG, Dennis.

    EDIT 1: Ich sehe gerade, dass ein Christian Tauschek das selbe Problem hatte, und offenbar mit ihm angebotenen Quellcodes von Peter Götz nicht zum Ziel kam. Mir geht das genauso. Auf die Quellcodes bin ich natürlich auch schon gestoßen. Aber wie bei ihm handelt es sich bei mir um ein DGV und nicht das DG. Und was Peter damals mit einem "eben eine eigene DGVComboBoxColumn selber schreiben" bezeichnet, bereitet mir eben arge Probleme. Offenbar Christian ebenso. Der Thread endet jedenfalls nicht so, als wären alle fragen beantwortet. Vielleicht hat er es allerdings inzwischen gelöst ... an der Lösung wäre ich dann sehr interessiert. :-)

    Freitag, 29. Oktober 2010 07:51

Alle Antworten

  • Hallo,

    Ein erster Versuch mit Hilfe einer Quelle im Web ist zum Glück
    gelungen. Speziell geht es bei meinem zweiten Versuch darum,
    einer ComboBoxCell eines DGV abzugewöhnen, nur Listform
    zu sein, sondern auch Eingabefeld (DropDownStyle=DropDown).
    Das ist mir sogar gelungen.

    Ich rate mal, dass es Dir gelungen ist, die ComboBox im DGV
    sichtbar zu machen. Dass diese dann auch mit allen ihren
    möglichen Funktionalitäten korrekt arbeitet, bezweifle ich ein
    wenig.

    Dummerweise geht danach nur nix.
    Die Eingabe geht bei Return verloren,
    es findet keine Übernahme in die Zelle statt

    Dazu musst Du natürlich entpsrechenden Code schreiben.

    und der Focus geht in die nächste Zeile anstatt sinnigerweise
     in das nächste freie Feld der selben Zeile.

    Das ist ein leider wenig praxisnahes Standardverhalten des
    DataGridView, das man ändern sollte und ändern kann.
    Unter

        www.gssg.de -> Visual Basic -> VB.net
        -> DataGridView
            -> DataGridView Sort/Unsort

    gibt es ein Beispiel mit einem entspr. angepassten DGV.

    Ich verstehe auch zugegebenermaßen die innere
    Architektur dieses DGV nicht ganz. Vielleicht kann mir da ja ein
    erfahrener Komponentencoder mal auf die Sprünge helfen. (Bei zu
    umfangreichen und für die ganze Gruppe nicht mehr interessanten
    oder zu banalen Beschreibungen auch gerne per direkter PN.)

    Mit der ComboBoxColumn, die eine echte ComboBox mit allen
    DropDownStyles, also auch mit DropDownStyle = DropDown
    hast Du Dir ein reichlich kompexes Control vorgenommen, das
    nicht nur mit simplen Texten (wie eine TextBox in einer TextboxColumn),
    sondern auch mit komplexen Objekten arbeiten kann und das
    macht die Sache eben auch deutlich umfangreicher und leider
    auch unübersichtlicher.

    Ich bin gerade dabei eine DGVComboBoxColumn zu schreiben.
    Ist aber leider noch nicht fertig und wird wg. des doch nicht
    ganz geringen Umfanges noch eine Weile dauern.


    EDIT 1: Ich sehe gerade, dass ein Christian Tauschek das selbe
    Problem hatte, und offenbar mit ihm angebotenen Quellcodes von
    Peter Götz nicht zum Ziel kam.

    Es gibt auf meiner Internetpräsenz (www.gssg.de) ein Beispiel
    für eine ComboBoxColumn (mit allen DropDownStyles) für das
    ältere DataGrid.
    Du könntest also dieses Beispiel nutzen. Da das DataGrid
    die selbe Optik wie das DGV bietet und auch via

        DG.DataSource = Datenquelle

    gebunden werden kann wäre das eine sehr wohl praktikable
    Lösung.

    Mir geht das genauso. Auf die Quellcodes bin ich natürlich auch
    schon gestoßen. Aber wie bei ihm handelt es sich bei mir um ein
    DGV und nicht das DG.

    Was spricht denn gegen die Verwendung des DataGrid anstatt
    des DataGridView?

    Und was Peter damals mit einem "eben eine eigene
    DGVComboBoxColumn selber schreiben" bezeichnet, bereitet
    mir eben arge Probleme.

    Nicht nur Dir. ;-)

    Offenbar Christian ebenso. Der Thread endet jedenfalls nicht so,
    als wären alle fragen beantwortet. Vielleicht hat er es allerdings
    inzwischen gelöst ... an der Lösung wäre ich dann sehr interessiert. :-)

    Wie schon erwähnt, arbeite ich gerade an einer solchen "Lösung".
    Gerade mit der ComboBox gibt es vieles mehr zu beachten, als
    beim in vieler Hinsicht einfacheren CalendarControl.
    Bis zu meiner fertigen Lösung wird es deshalb noch eine Weile
    dauern.

    In vielen Fällen ist es möglich das DataGridView ohne oder zumindest
    ohne grosse Codeänderungen durch ein DataGrid und umgekehrt ein
    DataGrid durch ein DataGridView zu ersetzen.
    Du müsstest also mal konkretisieren, warum Du kein DataGrid
    verwenden möchtest bzw. kannst.

    Gruß aus St.Georgen
    Peter Götz
    www.gssg.de (mit VB-Tipps u. Beispielprogrammen)

    Samstag, 30. Oktober 2010 18:37
  • Hallo vbbedi,
    bitte verwende deinen Realnamen. Ich habe zufällig gelesen, dass auch ich in deinem Posting vorkomme. Ja ich hatte das Problem mit der ComboBoxColumn, welches ich aber nun gelöst habe. Siehe untenstehender Code. Einiges davon kommt von Peter. Beachte aber die Sub "OnSelectedIndexChanged" bei der ComboBox in der Class ComboBoxAutoCompleteEditingControl.
    Diese ist nämlich notwendig, damit der Wert auch im Fall von DropDownStyle = DropDownList übernommen wird.

    Damit ein Wert auch nach drücken von Return übernommen werden kann, dann sieh dir die Function ProcessCmdKey an: (zB.: bei einem CalendarControl)

    Untenstehend drei Codeblöcke, die so ziemlich alle deine Probleme lösen dürften. Und das alles mit einem DataGridView ohne das alte DataGrid verwenden zu müssen.

    mfg
    Christian Tauschek

     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''Beginn Block 1''''''''''''''''''''''''''''''''''''''''''''''''''

    #Region

    "Klassen, die es ermglichen ein Kalender Steuerelement innerhalb eines DataGridView zu verwenden"

    Public Class DataGridViewCalendarColumn

    Inherits DataGridViewColumn

    Public Sub New()

    MyBase.New(New CalendarCell)

    End Sub

     

    "Properties"

    Public Overrides Property CellTemplate() As DataGridViewCell

    Get

    Return MyBase.CellTemplate

    End Get

    Set(ByVal value As DataGridViewCell)

    ' Ensure that the cell used for the template is a CalendarCell.

    If (value IsNot Nothing) AndAlso _

    Not value.GetType().IsAssignableFrom(GetType(CalendarCell)) _

    Then

    Throw New InvalidCastException("Must be a CalendarCell")

    End If

    MyBase.CellTemplate = value

    End Set

    End Property

     

    Region

    End Class

    Public Class CalendarCell

    Inherits DataGridViewTextBoxCell

    Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, _

    ByVal initialFormattedValue As Object, _

    ByVal dataGridViewCellStyle As DataGridViewCellStyle)

    ' Set the value of the editing control to the current cell value.

    MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, _

    dataGridViewCellStyle)

    Dim ctl As CalendarEditingControl = _

    CType(DataGridView.EditingControl, CalendarEditingControl)

    ' Use the default row value when Value property is null.

    If (Me.Value Is Nothing Or TypeOf (Me.Value) Is DBNull) Then

    ctl.Value = CType(DateTime.Now, DateTime) 'das heutige Datum

    Else

    ctl.Value = CType(Me.Value, DateTime)

    End If

    End Sub

     

    "Properties"

    Public Overrides ReadOnly Property EditType() As Type

    Get

    ' Return the type of the editing control that CalendarCell uses.

    Return GetType(CalendarEditingControl)

    End Get

    End Property

    Public Overrides ReadOnly Property ValueType() As Type

    Get

    ' Return the type of the value that CalendarCell contains.

    Return GetType(DateTime)

    End Get

    End Property

    Public Overrides ReadOnly Property DefaultNewRowValue() As Object

    Get

    Return Nothing 'standardmig ist in der Zelle kein Datum eingetragen

    End Get

    End Property

     

    Region

    End Class

    Class CalendarEditingControl

    Inherits DateTimePicker

    Implements IDataGridViewEditingControl

    Private dataGridViewControl As DataGridView

    Private valueIsChanged As Boolean = False

    Private rowIndexNum As Integer

    Public Sub New()

    Me.Format = DateTimePickerFormat.Short

    End Sub

    Public Function GetEditingControlFormattedValue(ByVal context _

    As DataGridViewDataErrorContexts) As Object _

    Implements IDataGridViewEditingControl.GetEditingControlFormattedValue

    Return Me.Value.ToShortDateString()

    End Function

    Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As _

    DataGridViewCellStyle) _

    Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl

    Me.Font = dataGridViewCellStyle.Font

    Me.CalendarForeColor = dataGridViewCellStyle.ForeColor

    Me.CalendarMonthBackground = dataGridViewCellStyle.BackColor

    End Sub

    Public Function EditingControlWantsInputKey(ByVal key As Keys, _

    ByVal dataGridViewWantsInputKey As Boolean) As Boolean _

    Implements IDataGridViewEditingControl.EditingControlWantsInputKey

    ' Let the DateTimePicker handle the keys listed.

    Select Case key And Keys.KeyCode

    Case Keys.Left, Keys.Up, Keys.Down, Keys.Right, _

    Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp

    Return True

    Case Else

    Return Not dataGridViewWantsInputKey

    End Select

    End Function

    Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) _

    Implements IDataGridViewEditingControl.PrepareEditingControlForEdit

    ' No preparation needs to be done.

    End Sub

    Protected Overrides Sub OnValueChanged(ByVal eventargs As EventArgs)

    ' Notify the DataGridView that the contents of the cell have changed.

    valueIsChanged = True

    Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)

    MyBase.OnValueChanged(eventargs)

    End Sub

    Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean

    'wenn die 'Enter' - Taste gedrckt wurde, dann wird der angezeigte Datumswert bernommen

    If keyData = Keys.Return Then

    Date.TryParse(Me.Text, Me.Value)

    End If

    Return MyBase.ProcessCmdKey(msg, keyData)

    End Function

     

    "Properties"

    Public Property EditingControlFormattedValue() As Object _

    Implements IDataGridViewEditingControl.EditingControlFormattedValue

    Get

    Return Me.Value.ToShortDateString()

    End Get

    Set(ByVal value As Object)

    Try

    ' This will throw an exception of the string is

    ' null, empty, or not in the format of a date.

    Me.Value = DateTime.Parse(CStr(value))

    Catch

    ' In the case of an exception, just use the default

    ' value so we're not left with a null value.

    Me.Value = DateTime.Now

    End Try

    End Set

    End Property

    Public Property EditingControlRowIndex() As Integer _

    Implements IDataGridViewEditingControl.EditingControlRowIndex

    Get

    Return rowIndexNum

    End Get

    Set(ByVal value As Integer)

    rowIndexNum = value

    End Set

    End Property

    Public ReadOnly Property RepositionEditingControlOnValueChange() _

    As Boolean Implements _

    IDataGridViewEditingControl.RepositionEditingControlOnValueChange

    Get

    Return False

    End Get

    End Property

    Public Property EditingControlDataGridView() As DataGridView _

    Implements IDataGridViewEditingControl.EditingControlDataGridView

    Get

    Return dataGridViewControl

    End Get

    Set(ByVal value As DataGridView)

    dataGridViewControl = value

    End Set

    End Property

    Public Property EditingControlValueChanged() As Boolean _

    Implements IDataGridViewEditingControl.EditingControlValueChanged

    Get

    Return valueIsChanged

    End Get

    Set(ByVal value As Boolean)

    valueIsChanged = value

    End Set

    End Property

    Public ReadOnly Property EditingControlCursor() As Cursor _

    Implements IDataGridViewEditingControl.EditingPanelCursor

    Get

    Return MyBase.Cursor

    End Get

    End Property

     

    Region

    End Class

     

    Region

     

    #End

     

    #End

     

    #Region

     

    #End

     

    #Region

     

    #End

     

    #Region

     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''Beginn Block 2''''''''''''''''''''''''''''''''''''''''''''''''''
    #Region "Funktionen, damit beim Drücken der Enter-Taste nach rechts und nicht nach unten gesprungen wird"
     ' gsDataGridView ist vom DataGridView abgeleitet
     '
     ' gsDataGridView hat gegenüber dem normalen DataGridView
     ' ein verändertes Verhalten beim Drücken der Eingabetaste.
     '
     ' DataGridView wechselt beim Drücken der Eingabetaste 
     ' in die erstejeweils darunterliegende Zeile/Zelle, 
     ' diese Verhalten ist wenig praxisgerecht.
     ' 
     ' gsDataGridView wechselt beim Drücken der Eingabetaste
     ' in die nächste, rechts daneben liegende Zelle der selben
     ' Zeile und erst beim Drücken der Eingabetaste in der
     ' letzten (rechten) Zelle einer Zeile zur ersten (linken)
     ' sichtbaren, nicht schreibgeschützten Zelle der nächsten
     ' Zeile. Sind alle Spalten schreibgeschützt, wird zu letzten 
     ' sichtbaren Spalte der nächsten Zeile gewechselt.
     '
     ' Alle übrigen Funktionalitäten entsprechen dem normalen 
     ' DatagridView.
    
     Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
     ' Prüfen ob Eingabetaste gedrückt wurde
     If (keyData And Keys.KeyCode) = Keys.Enter Then
    
     ' Eingabe an ProcessRightKey umleiten
     Return Me.ProcessRightKey(keyData)
    
     End If
    
     ' Normale Ereignisbehandlung für alle übrigen Tasten
     Return MyBase.ProcessDialogKey(keyData)
     End Function
    
     Private Shadows Function ProcessRightKey(ByVal keyData As Keys) As Boolean
     ' Prüfen, ob es sich um die umgeleitete Eingabetaste handelt.
     If (keyData And Keys.KeyCode) = Keys.Enter Then
    
     Dim DGVC As DataGridViewCell = MyBase.CurrentCell
    
     ' DGVC is Nothing kann vorkommen, wenn für alle 
     ' Spalten .Columns.Visible = False gesetzt ist.
     If DGVC IsNot Nothing Then
    
     Dim RowIndex As Integer = MyBase.Rows(MyBase.CurrentCell.RowIndex).Index
     Dim ColIndex As Integer = MyBase.CurrentCell.ColumnIndex
     Dim LastVisibleCol As Integer = -1
     Dim NewColIndex As Integer = -1
    
     ' NewColIndex ermitteln
     Dim i As Integer
    
     Do While NewColIndex < 0
      For i = (ColIndex + 1) To (MyBase.Columns.Count - 1)
      If MyBase.Rows(RowIndex).Cells(i).Visible Then
      LastVisibleCol = i
      If MyBase.Rows(RowIndex).Cells(i).ReadOnly = False Then
      NewColIndex = i
      Exit Do
      End If
      End If
      Next
      ' Wenn im ersen Durchlauf der for-Schleife 
      ' keine nicht schreibgeschützte 
      ' Zelle gefunden wurde, in der 
      ' nächsten Zeile weitersuchen.
      If NewColIndex < 0 Then
      RowIndex = RowIndex + 1
      ColIndex = 0
      End If
      If RowIndex > (MyBase.Rows.Count - 1) Then
      Exit Do
      End If
     Loop
    
     If RowIndex < MyBase.Rows.Count Then
      Try
      MyBase.CurrentCell = MyBase.Rows(RowIndex).Cells(NewColIndex)
      Catch ex As Exception
      'diese Try-Catch musste ich einfügen, da in bestimmten Umständen die obige Routine zu einem Fehler führt
      'warum das so ist weiß ich nicht
      End Try
      Return True
     End If
     End If
     End If
    
     ' Normale Ereignisbehandlung, wenn 
     ' nicht die Eingabetaste gedrückt war
     Return MyBase.ProcessRightKey(keyData)
     End Function
    
     Protected Overrides Function ProcessDataGridViewKey(ByVal e As System.Windows.Forms.KeyEventArgs) As Boolean
     ' Prüfen, ob Taste Enter gedrückt wurde
     If e.KeyCode = Keys.Enter Then
    
     ' Umleiten an ProcessRightKey
     Return Me.ProcessRightKey(e.KeyData)
     End If
    
     ' Normale Ereignisbehandlung, wenn 
     ' nicht die Eingabetaste gedrückt war
     Return MyBase.ProcessDataGridViewKey(e)
     End Function
    #End Region
     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''Beginn Block 3''''''''''''''''''''''''''''''''''''''''''''''''''
    #Region "Klassen, die es ermöglichen ein ComboBoxAutoComplete Steuerelement innerhalb eines DataGridView zu verwenden"
    
     'eine ComboBox, die eine Vorschlagsliste während des Eingebens anzeigt
     Public Class ComboBoxAutoComplete
     Inherits ComboBox
    
     Public Sub New()
     With Me
     .AutoCompleteSource = AutoCompleteSource.ListItems
     .AutoCompleteMode = AutoCompleteMode.Suggest
     End With
     End Sub
    
    #Region "Properties"
     Public Property DataGridViewComboBoxAutoCompleteParameters() As DataGridViewComboBoxAutoCompleteParameters
     Get
     Dim DGVCBACP As New DataGridViewComboBoxAutoCompleteParameters
     With DGVCBACP
      .MaxInputLength = Me.MaxLength
      .DataSource = Me.DataSource
      .ValueMember = Me.ValueMember
      .DropDownStyle = Me.DropDownStyle
     End With
     Return DGVCBACP
     End Get
     Set(ByVal value As DataGridViewComboBoxAutoCompleteParameters)
     With Me
      Me.MaxLength = value.MaxInputLength
      Me.DataSource = value.DataSource
      Me.ValueMember = value.ValueMember
      Me.DropDownStyle = value.DropDownStyle
     End With
     End Set
     End Property
    #End Region
    
     End Class
    
     'die Spalte, die eine ComboBoxAutoComplete enthält
     Public Class DataGridViewComboBoxAutoCompleteColumn
     Inherits DataGridViewColumn
    
     'beim Anlegen der ComboBoxAutoCompleteCell werden gleich die Einstellungen der ComboBox verwendet
     Public Sub New(ByVal DataGridViewComboBoxAutoCompleteParameters As DataGridViewComboBoxAutoCompleteParameters)
     Dim CBACC As New ComboBoxAutoCompleteCell
     CBACC.Tag = DataGridViewComboBoxAutoCompleteParameters 'im TAG der Zellen-Vorlage werden alle Parameter einschließlich der Auflistung für die DataGridViewComboBoxAutoComplete übergeben 
     MyBase.CellTemplate = CBACC
     End Sub
    
    #Region "Properties"
    
     Public Overrides Property CellTemplate() As DataGridViewCell
     Get
     Return MyBase.CellTemplate
     End Get
     Set(ByVal value As DataGridViewCell)
    
     ' Ensure that the cell used for the template is a ComboBoxAutoCompleteCell.
     If (value IsNot Nothing) AndAlso _
      Not value.GetType().IsAssignableFrom(GetType(ComboBoxAutoCompleteCell)) _
      Then
      Throw New InvalidCastException("Must be a ComboBoxAutoCompleteCell")
     End If
     MyBase.CellTemplate = value
    
     End Set
     End Property
    
    #End Region
    
     End Class
    
     Public Class ComboBoxAutoCompleteCell
     Inherits DataGridViewTextBoxCell
    
     'diese Sub wird aufgerufen, wenn die Zelle editiert wird und dadurch muss die ComboBox initialisiert und angezeigt werden
     Public Overrides Sub InitializeEditingControl(ByVal rowIndex As Integer, ByVal initialFormattedValue As Object, ByVal dataGridViewCellStyle As DataGridViewCellStyle)
    
     ' Set the value of the editing control to the current cell value.
     MyBase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)
    
     With CType(DataGridView.EditingControl, ComboBoxAutoCompleteEditingControl)
    
     'Einstellungen für die anzuzeigende ComboBox übergeben
     .DataGridViewComboBoxAutoCompleteParameters = CType(Me.Tag, DataGridViewComboBoxAutoCompleteParameters)
    
     Dim ACSC As New AutoCompleteStringCollection
     For Each r As DataRow In CType(.DataGridViewComboBoxAutoCompleteParameters.DataSource, DataView).Table.Rows
      ACSC.Add(CStr(r(.DataGridViewComboBoxAutoCompleteParameters.ValueMember)))
     Next
    
     ' AutoComplete-Auflistung für ComboBox 
     .AutoCompleteCustomSource = ACSC
    
     ' Use the default row value when Value property is null.
     If (Me.Value Is Nothing Or TypeOf (Me.Value) Is DBNull) Then
      .Text = String.Empty
     Else
      .Text = CType(Me.Value, String)
     End If
     End With
    
     End Sub
    
    #Region "Properties"
    
     Public Overrides ReadOnly Property EditType() As Type
     Get
     ' Return the type of the editing control that ComboBoxAutoCompleteCell uses.
     Return GetType(ComboBoxAutoCompleteEditingControl)
     End Get
     End Property
    
     Public Overrides ReadOnly Property ValueType() As Type
     Get
     ' Return the type of the value that ComboBoxAutoCompleteCell contains.
     Return GetType(String)
     End Get
     End Property
    
     Public Overrides ReadOnly Property DefaultNewRowValue() As Object
     Get
     ' Use the current String as the default value.
     Return String.Empty
     End Get
     End Property
    
    #End Region
    
     End Class
    
     Class ComboBoxAutoCompleteEditingControl
     Inherits ComboBoxAutoComplete
     Implements IDataGridViewEditingControl
    
     Private dataGridViewControl As DataGridView
     Private valueIsChanged As Boolean = False
     Private rowIndexNum As Integer
    
     Public Function GetEditingControlFormattedValue(ByVal context _
     As DataGridViewDataErrorContexts) As Object _
     Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
    
     Return Me.Text
    
     End Function
    
     Public Sub ApplyCellStyleToEditingControl(ByVal dataGridViewCellStyle As _
     DataGridViewCellStyle) _
     Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl
    
     Me.Font = dataGridViewCellStyle.Font
     Me.ForeColor = dataGridViewCellStyle.ForeColor
     Me.BackColor = dataGridViewCellStyle.BackColor
    
     End Sub
    
     Public Function EditingControlWantsInputKey(ByVal key As Keys, _
     ByVal dataGridViewWantsInputKey As Boolean) As Boolean _
     Implements IDataGridViewEditingControl.EditingControlWantsInputKey
    
     ' Let the ComboBoxAutoComplete handle the keys listed.
     Select Case key And Keys.KeyCode
     Case Keys.Left, Keys.Up, Keys.Down, Keys.Right, _
      Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp
    
      Return True
    
     Case Else
      Return Not dataGridViewWantsInputKey
     End Select
    
     End Function
    
     Public Sub PrepareEditingControlForEdit(ByVal selectAll As Boolean) _
     Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
    
     ' No preparation needs to be done.
    
     End Sub
    
     Protected Overrides Sub OnTextChanged(ByVal eventargs As EventArgs)
    
     ' Notify the DataGridView that the contents of the cell have changed.
     valueIsChanged = True
     Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
     MyBase.OnTextChanged(eventargs)
    
     End Sub
    
     Protected Overrides Sub OnSelectedIndexChanged(ByVal e As System.EventArgs)
    
     'diese Sub ist notwendig, da ansonsten der Cell-Wert nicht übernommen wird, wenn die ComboBox auf DropDownStyle = DropDownList eingestellt ist
     valueIsChanged = True
     Me.EditingControlDataGridView.NotifyCurrentCellDirty(True)
     MyBase.OnSelectedIndexChanged(e)
    
     End Sub
    
    #Region "Properties"
    
     Public ReadOnly Property RepositionEditingControlOnValueChange() _
     As Boolean Implements _
     IDataGridViewEditingControl.RepositionEditingControlOnValueChange
    
     Get
     Return False
     End Get
    
     End Property
    
     Public Property EditingControlFormattedValue() As Object _
     Implements IDataGridViewEditingControl.EditingControlFormattedValue
    
     Get
     Return Me.Text
     End Get
    
     Set(ByVal value As Object)
     Me.Text = CStr(value)
     End Set
    
     End Property
    
     Public Property EditingControlRowIndex() As Integer _
     Implements IDataGridViewEditingControl.EditingControlRowIndex
    
     Get
     Return rowIndexNum
     End Get
     Set(ByVal value As Integer)
     rowIndexNum = value
     End Set
    
     End Property
    
     Public Property EditingControlDataGridView() As DataGridView _
     Implements IDataGridViewEditingControl.EditingControlDataGridView
    
     Get
     Return dataGridViewControl
     End Get
     Set(ByVal value As DataGridView)
     dataGridViewControl = value
     End Set
    
     End Property
    
     Public Property EditingControlValueChanged() As Boolean _
     Implements IDataGridViewEditingControl.EditingControlValueChanged
    
     Get
     Return valueIsChanged
     End Get
     Set(ByVal value As Boolean)
     valueIsChanged = value
     End Set
    
     End Property
    
     Public ReadOnly Property EditingControlCursor() As Cursor _
     Implements IDataGridViewEditingControl.EditingPanelCursor
    
     Get
     Return MyBase.Cursor
     End Get
    
     End Property
    
    #End Region
    
     End Class
    
     'hier werden die Werte zum Einstellen der ComboBox übergeben
     Public Class DataGridViewComboBoxAutoCompleteParameters
     Private _MaxInputLength As Integer 'der Wert der maximalen Eingabelänge wird allen ComboBoxAutoCompleteCell - Klassen zur Verfügung gestellt
     Private _DataSource As Object 'die Datenquelle für die ComboBox wird jeder ComboBox zur Verfügung gestellt
     Private _ValueMember As String 'das ist der Name der Spalte, die die ComboBox in der Auflistung anzeigen soll
     Private _DropDownStyle As ComboBoxStyle = ComboBoxStyle.DropDown 'der DropDownStyle (zB.: DropDown als Default)
    
    #Region "Properties"
     'hier wird die maximal mögliche Eingabelänge festgelegt
     Public Property MaxInputLength() As Integer
     Get
     Return _MaxInputLength
     End Get
     Set(ByVal value As Integer)
     _MaxInputLength = value
     End Set
     End Property
    
     'die Datenquelle für die Auflistung in der ComboBox
     Public Property DataSource() As Object
     Get
     Return _DataSource
     End Get
     Set(ByVal value As Object)
     _DataSource = value
     End Set
     End Property
    
     'der Name der Spalte, die die ComboBox in der Auflistung anzeigen soll
     Public Property ValueMember() As String
     Get
     Return _ValueMember
     End Get
     Set(ByVal value As String)
     _ValueMember = value
     End Set
     End Property
    
     'der DropDownStyle (zB.: DropDownList)
     Public Property DropDownStyle() As ComboBoxStyle
     Get
     Return _DropDownStyle
     End Get
     Set(ByVal value As ComboBoxStyle)
     _DropDownStyle = value
     End Set
     End Property
    #End Region
    
     End Class
    
    #End Region
    Samstag, 30. Oktober 2010 21:39
  • Erstmal danke für deine Codeblöcke, Christian.

    Ich habe sie eben eingebaut, und teste nun damit herum. Was mir auffällt:

    - Ein Fehler tritt auf, wenn das DGV noch ohne Zeilen ist (also nur mit NEW erstellt und dann eine Spalte deiner AutoCompleteColumn eingefügt). Dieser Fehler (NullReferenceException) tritt auf bei:

     

    For Each r As DataRow In CType(.DataGridViewComboBoxAutoCompleteParameters.DataSource, DataView).Table.Rows

    ACSC.Add(

    CStr(r(.DataGridViewComboBoxAutoCompleteParameters.ValueMember)))

     

    Next

    - Was mir noch nicht ganz klar ist: wo binde ich die drei Key-Routinen aus Block 2 ein? Im Hauptcode?

    - Der erste Block macht mich etwas stutzig, denn beim Einbinden rief der zig Fehler hervor. Ich weiss nicht, woran das gerade liegt, aber da er auch eher die CalenderCell behandelt, lass ich den mal fürs erste beiseite.

    Die anderen Teile aus Block 3 (zumindest die, an denen ich gerade herumteste) habe ich ausgelagert in eine neue Klassendatei. Denke mal, so war das auch gedacht. Ich lager sowas immer gerne aus, in externe Dateien, damit ich es leicht in anderen Programmen erneut einbinden kann.

    Ich teste mal weiter, bis später ...

    LG, Dennis.

    Mittwoch, 3. November 2010 10:56
  • Also das klappt irgendwie noch nicht ... ich habe jetzt mal ein kleines Testprogramm geschrieben, das so eine Spalte erstellt:

     

    Dim MyPars As New DataGridViewComboBoxAutoCompleteParameters

     

    Dim CB As New ComboBox

    CB.Items.Clear()

    CB.Items.Add(

    "Meins")

    CB.Items.Add(

    "Deins")

    CB.Items.Add(

    "Unsers")

    MyPars.DropDownStyle = ComboBoxStyle.DropDown

    MyPars.DataSource = CB.DataSource

    MyPars.MaxInputLength = -1

    MyPars.ValueMember =

    ""

     

    Dim NewCol As New DataGridViewComboBoxAutoCompleteColumn(MyPars)

    MyDGV.Columns.Add(NewCol)

    MyDGV.AllowUserToAddRows =

    False

    MyDGV.AllowUserToDeleteRows =

    False

    MyDGV.AllowUserToOrderColumns =

    True

    MyDGV.Rows.Add(

    "Test")

    Die Zeile Test scheint auch. Aber wenn ich daraufklicke kommt eine NullRefException. In der oben bereits geposteten Zeile mit dem "For Each r as DataRow" ...

    Hab ich da irgendwas entscheidendes übersehen? Was ich auch noch nicht ganz schnalle ist, wie du die Parameter im Tag übergibst. Denn für mich sieht es so aus, als kämen dort gar keine Parameter an ...

    Vielleicht kannst du mir nochmal auf die Sprünge helfen. :-)

    LG, Dennis.

    Mittwoch, 3. November 2010 11:55
  • Also ich glaube nach einigem Hin- und Herprobieren bin ich dank Christians Code meinem Ziel sehr nahe.

    Wenn ich mit meinem Ergebis zufrieden bin, poste ich gerne hier auch mal meine fertige Klasse.

    LG, Dennis.

    Mittwoch, 3. November 2010 14:51
  • Hallo Dennis, da ich jetzt nicht weiß wie weit du gekommen bist und wo du noch Probleme hast, gib einfach Bescheid, wenn du noch Schwierigkeiten hast.. MfG Christian Tauschek
    Mittwoch, 3. November 2010 21:31