DataGridView Ändern der SelectionBackColor bei Focusänderung eines DGV

    • VB.NET

    Es gibt 1 Antwort in diesem Thema. Der letzte Beitrag () ist von Storch.

      DataGridView Ändern der SelectionBackColor bei Focusänderung eines DGV

      Von ListViews kenne ich es, dass, sofern die Eigenschaft 'HideSelection' auf False steht, beim Verlassen des ListViews die Selektion einer Zeile erhalten bleibt, jedoch andersfarbig. Dadurch erkennt man die zuletzt selektierte Zeile, hat aber nicht den Eindruck, dass die Zeile bzw. das Listview noch den Focus haben.

      Mir ist aufgefallen, das DataGridViews dieses Verhalten nicht zeigen, beim Verlassen eines DGV bleibt die Selektion mit der "vollen" 'SelectionBackColor' erhalten. Setzt man den Focus in ein weiteres DGV, sieht es so aus, als ob beide DGV's den Focus haben. Trotz einiger Recherchen fand ich keinen Weg, dieses mit "Bordmitteln" zu ändern (was nicht heißt, dass es nicht doch irgendwelche Wege dafür gibt). Daher ist folgende Lösung entstanden:

      Zunächst habe ich eine Erweiterungsmethode für das DataGridView geschrieben:

      VB.NET-Quellcode

      1. <Extension()> _
      2. Public Sub ChangeSelectionBackColor(Of T As DataGridView)(ByVal dgv As DataGridView, ByVal selColor As Color, ByVal markColor As Color)
      3. If dgv.Focused Then
      4. dgv.DefaultCellStyle.SelectionBackColor = selColor
      5. dgv.DefaultCellStyle.SelectionForeColor = Color.Black
      6. Else
      7. If markColor = Color.Transparent Then
      8. dgv.ClearSelection()
      9. Else
      10. dgv.DefaultCellStyle.SelectionBackColor = markColor
      11. dgv.DefaultCellStyle.SelectionForeColor = Color.Black
      12. End If
      13. End If
      14. End Sub


      Übergeben werden an diese Methode das DataGridView selbst und die Parameter selColor und markColor

      selColor vertritt die Selektionsfarbe, wenn das DGV den Focus hat,
      markColor vertritt die Selektionsfarbe, wenn das DGV den Focus nicht hat

      Die If-Anweisung prüft, ob das DGV den Focus hat und im Then-Zweig werden die Selektionsfarben entsprechend definiert. Der Else-Zweig stellt die alternativen Selektionsfarben ein.

      Die zweite If-Then-Anweisung dient der Möglichkeit, die Selektion des DGV nach Focusverlust vollständig aufzuheben. Color.Transparent hat keine sichtbaren Auswirkungen auf die SelectionBackColor (die zuletzt eingestellten Farben werden durch Transparent ja nicht verdeckt) , so dass dieser Farbwert dazu hergenommen wird, um ein 'ClearSelection' auszuführen. Bei allen anderen Farbwerten im Parameter markColor wird der Else-Zweig ausgeführt.

      Die Definition der SelectionForeColor sollte passend zu BackColor erfolgen. Im Beispiel habe ich schwarz gewählt.

      Angewendet wird die Erweiterungsmethode sinnvoller weise in den Ereignissen DataGridView.Enter -u. .Leave:

      VB.NET-Quellcode

      1. Private Sub dgv_attach_Enter(sender As Object, e As EventArgs) Handles dgv_attach.Enter
      2. Me.dgv_attach.ChangeSelectionBackColor(Of DataGridView)(Color.Orange, Me.BackColor)
      3. End Sub
      4. Private Sub dgv_attach_Leave(sender As Object, e As EventArgs) Handles dgv_attach.Leave
      5. 'Me.dgv_attach.ClearSelection()
      6. Me.dgv_attach.ChangeSelectionBackColor(Of DataGridView)(Color.Orange, Color.Transparent)
      7. End Sub


      Bei Enter hat das DGV den Focus bereits erhalten, bei Leave bereits verloren, so dass

      VB.NET-Quellcode

      1. If dgv.Focused Then
      in der Erweiterungsmethode sicher greift.
      Die auskommentierte Zeile in dgv_attach_Leave wird durch die oben erklärte Anwendung von Color.Transparent überflüssig.

      Für die erstmalige Fokussierung eines DGV's und Einstellung der Farben kann wie folgt vorgegangen werden (Shown tritt nur bei erstmaligen Anzeigen eines Forms ein):

      VB.NET-Quellcode

      1. Private Sub frm_email_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
      2. Me.dgv_emails.Focus()
      3. Me.dgv_emails.ChangeSelectionBackColor(Of DataGridView)(Color.Orange, Me.BackColor)
      4. End Sub

      Ich hoffe, ich habe alles vernünftig erklärt und der Tipp ist für jemandem von Nutzen.
      GUD Uwe

      :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!

      DGV SelectionColors... Modifikationen und Beispielprojekt

      Ich habe jetzt ein Beispielprojekt zu meinem Tipp erstellt. Siehe Anhänge.

      Es ist abgekoppelt von meinem Email-Versender, den ich grad schreibe. Das obere DGV zeigt Email-Daten, das untere DGV zeigt Dateianhänge. Darunter zwei Textboxes. Die Daten sind aus der Luft gegriffen und fest hinterlegt. Das Dataset wird mit ‚ReadXML‘ nur gelesen. ‚WriteXML‘ wird nicht angewendet.

      Das Form frm_appstart hat eine Private Member namens m_ActivateExtension vom Typ Boolean. In der Public Sub New() kann der Wert dieser Membervariable geändert werden:
      • False = Extension deaktiviert = Standardselektionsverhalten
      • True = Extension ist aktiviert = modifiziertes Selektionsverhalten

      Im Download ist False eingestellt. So wird nach Start des Beispiels zunächst das normale Selektionsverhalten gezeigt. Zur Verwendung der Extension ist die Variable auf True zu setzen. Wer das Beispiel für seine Zwecke verwendet, braucht die Variable und die zugehörigen If’s natürlich nicht.

      Der Tipp aus Post 1 ist natürlich in dem Beispielprojekt enthalten, jedoch habe ich einiges grundlegend verändert bzw. erweitert:
      • Als Parameter dient jetzt neben den DGV die Enumeration enSelColor, die die Extension steuert
      • Color.Transparent wird nicht mehr zum Aufheben der Selektion „mißbraucht“
      • Die Farben werden jetzt in der Extension definiert. Es werden SelectionBackColor und SelectionForeColor geführt, jeweils für die Selektion (DGV hat Focus) und die Markierung (DGV hat Focus nicht)
      • Zusätzlich zum RowsDefaultCellStyle wird der RowHeadersDefaultCellStyle manipuliert, wodurch auch der RowHeader selbst dem Selektionsverhalten folgt
      • Der optionale Parameter index erlaubt es, eine Zeile zielgerichtet zu markieren(siehe Text)

      An dieser Stelle bitte ich, die beigefügten vier Screenshots anzusehen. Bild1 zeigt das Selektionsverhalten ohne weitere Maßnahmen, Bilder 2 bis 4 das Selektionsverhalten unter Verwendung der Extension. Am unteren Bildrand habe ich Bemerkungen hingeschrieben. Ich denke, die Bilder veranschaulichen ganz gut, was die Extension macht.
      Rein visuell ist immer deutlich zusehen, wo gerade Aktivität zu verzeichnen ist, sprich, welches DGV den Focus hat, bzw. welche Zeile als Bezug dient, auch wenn der Focus abgegeben wurde.

      Note:
      In Post 1 habe ich in der Extension den Focus des jeweiligen DGV geprüft und auf das Ergebnis reagiert. Bei der Erstellung der Erweiterungen in diesem Beispiel, lag der Focus zuweilen nicht so, wie ich ihn erwartet habe. Da ich keine passenderen Events fand und im Zweifelsfall nicht noch die Focus-Methode einsetzen wollte, habe ich mich für die Enumeration als Parameter entschieden.


      Die modi der Extension:
      • scSelect
        Anzuwenden auf das DGV, das den Focus bekommt (i.d.R. bei DGV.Enter)
        Die Selektionsfarben werden auf selBackColor bzw. selForeColor eingestellt
      • scMark
        Anzuwenden auf das DGV, das den Focus verliert (i.d.R. bei DGV.Leave)
        Die Selektionsfarben werden auf markBackColor bzw. markForeColor eingestellt
        Hier kommt noch der optionale Parameter index in’s Spiel. Siehe Unten
      • scClear
        Hebt die Selektion des entsprechenden DGV auf. Im Beispiel angewendet auf das untere DGV, ausgelöst im Event TblEmailsBindingSource_PositionChanged , wodurch bei jedem Wechsel der Zeilen im oberen DGV, die Selektion des unteren aufgehoben wird. Da dieses Ereignis beim Start des Forms aber leider nicht greift, bedarf es eines zusätzlichen Aufrufes in dem Event frm_appstart_Shown , welches nur einmal bei Formularstart eintritt.

      Der optionale Parameter index

      Note:
      In meinem Mail-Versender habe ich zwei Textboxen ‚Betreff‘ und ‚Nachricht‘, die an die gleiche BindingSource gebunden sind, wie mein Email-DGV, welches bei mir zudem ReadOnly gesetzt ist. Das DGV bietet mir eine Übersicht über die Mails, die Textboxen bieten mehr Platz zum Schreiben.


      Im Beispiel sind die beiden Textboxen an die selbe BindingSource gebunden wie das untere DGV.
      Bei Verwendung der Extension wird gleich nach dem Start die Selektion des unteren DGV aufgehoben. Trotz fehlender Selektion steht der Index des unteren DGV dennoch auf der ersten Zeile (ich nenne das mal Zeilenmarkierung ), was durch den Pfeil angezeigt wird. Setz man nun den Cursor direkt in eine der beiden Textboxen, wird im Enter-Ereignis derselben die Extension mit den Parametern scMark und dem CurrentRow.Index des unteren DGV aufgerufen, wodurch die zugehörige Zeile grau markiert wird. Somit wird sofort ersichtlich, dass diese Zeile in Bearbeitung ist.

      In den TextBox.Enter Events wird mittels Me.dgv_attachments.SelectedCells.Count = 0 geprüft, ob irgendeine Zelle des unteren DGV’s selektiert ist. Diese Maßnahme unterdrückt den Aufruf der Extension, wenn z.B. zunächst eine Zeile des unteren DGV’s geklickt wurde und von diesem in die Textboxen gewechselt wird. In diesem Fall liegt die Selektion bzw. Markierung der Ursprungszeile ja bereits vor und muss nicht erneut ausgeführt werden.

      Wieder mal in der Hoffnung, alles vernünftig erklärt zu haben.. viel Spass damit.
      Bilder
      • Bsp_DGV_SelColor_WithoutExtension.JPG

        77,61 kB, 561×512, 510 mal angesehen
      • Bsp_DGV_SelColor_Extension1.JPG

        61,95 kB, 558×508, 349 mal angesehen
      • Bsp_DGV_SelColor_Extension2.JPG

        68,94 kB, 557×511, 381 mal angesehen
      • Bsp_DGV_SelColor_Extension3.JPG

        65,48 kB, 556×507, 266 mal angesehen
      Dateien
      GUD Uwe

      :whistling: Wenn ich genau wüsste, was ich nicht weiß, dann wäre mein Wissen vollständig!