Tooltip für DatagridHeader mit weniger XAML

  • WPF

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von eichseinet.

    Tooltip für DatagridHeader mit weniger XAML

    Hallo zusammen!

    Momentan geht's um Tooltips für den Header einer DataGrid.
    So funktioniert's im XAML:

    XML-Quellcode

    1. <DataGridTextColumn Header="Sendername" Binding="{Binding Sendername}">
    2. <DataGridTextColumn.HeaderStyle>
    3. <Style TargetType="DataGridColumnHeader">
    4. <Style.Triggers>
    5. <Trigger Property="IsMouseOver" Value="true">
    6. <Setter Property="ToolTip" Value="Style direkt der Spalte zugewiesen"/>
    7. <Setter Property="ToolTipService.ShowDuration" Value="60000"/>
    8. </Trigger>
    9. </Style.Triggers>
    10. </Style>
    11. </DataGridTextColumn.HeaderStyle>
    12. </DataGridTextColumn>


    Leider wurden nun aus einer Zeile gleich 12. Bei geschätzten 40 Spalten macht das 440 zusätzliche Zeilen. Ich konnte auch erfolgreich den Tooltip in die Resourcen der einzelnen DataGrid verschieben, aber dann ist der Text natürlich für alle Spalten gleich. Der Versuch nun den Text im Code zu überschreiben schlug fehl.

    VB.NET-Quellcode

    1. MeinGrid.Columns(0).HeaderStyle = ToolTip("Test")


    Legt man im XAML einfach den ToolTip wie folgt fest, dann erscheint kein Tooltip.

    XML-Quellcode

    1. <DataGridTextColumn Header="Sender-ID" Binding="{Binding SenderID}" ToolTipService.ToolTip="Test"/>


    Bevor ich nun ein StyleDictionary mit haufenweise einzelnen Styles und je einem Key erstelle, um die wiederum über HeaderStyle an jede Spalte zu übergeben, wollt ich mal fragen, ob's nicht doch etwas simpler geht.

    XML-Quellcode

    1. <DataGridTextColumn Header="Sender-ID" Binding="{Binding SenderID}" HeaderStyle="{StaticResource Mein_Key01}"/>


    Gruß

    eddi

    Neu

    Hallo Leute

    Tja, 40 Spalten.... naja. Gut. 4 Zeilen kann man schon mal einsparen weil es den Trigger gar nicht benötigt. es reicht ein Style mit Settern.
    Noch eine Zeile lässt sich sparen da die Duration ja nicht jedes mal angegeben werden muss. Sondern nur 1x z.b. in den Resourcen des DataGrids.

    XML-Quellcode

    1. <DataGridTextColumn Header="Sendername" Binding="{Binding Sendername}">
    2. <DataGridTextColumn.HeaderStyle>
    3. <Style TargetType="DataGridColumnHeader">
    4. <Setter Property="ToolTip" Value="Style direkt der Spalte zugewiesen"/>
    5. </Style>
    6. </DataGridTextColumn.HeaderStyle>
    7. </DataGridTextColumn>


    ABER
    Die schnellste Lösung welche mir einfallen würde wäre mittels Converter und Binding.

    Mein kleiner Test sieht wie folgt aus:

    XML-Quellcode

    1. <Window x:Class="MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    6. xmlns:local="clr-namespace:WpfApp1"
    7. mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" >
    8. <Window.Resources>
    9. <local:TestConverter x:Key="TestConverter"/>
    10. </Window.Resources>
    11. <Grid>
    12. <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding}" Tag="">
    13. <DataGrid.Resources>
    14. <Style TargetType="DataGridColumnHeader">
    15. <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource TestConverter}}"/>
    16. <Setter Property="ToolTipService.ShowDuration" Value="60000"/>
    17. </Style>
    18. </DataGrid.Resources>
    19. <DataGrid.Columns>
    20. <DataGridTextColumn Header="Vorname" Binding="{Binding Firstname}"/>
    21. <DataGridTextColumn Header="Nachname" Binding="{Binding LastName}"/>
    22. </DataGrid.Columns>
    23. </DataGrid>
    24. </Grid>
    25. </Window>


    und der Converter:

    VB.NET-Quellcode

    1. Imports System.Globalization
    2. Imports System.Windows.Controls.Primitives
    3. Public Class TestConverter
    4. Implements IValueConverter
    5. Private _tooltipKeyValuePairs As New List(Of KeyValuePair(Of String, String)) From
    6. {New KeyValuePair(Of String, String)("Vorname", "Der Tooltip für den Vornamen"),
    7. New KeyValuePair(Of String, String)("Nachname", "Der Tooltip für den Nachnamen")}
    8. Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
    9. If value.GetType() Is GetType(DataGridColumnHeader) AndAlso DirectCast(value, DataGridColumnHeader).DataContext IsNot Nothing Then
    10. Return _tooltipKeyValuePairs.Single(Function(x) x.Key = DirectCast(value, DataGridColumnHeader).DataContext).Value
    11. Else
    12. Return value.ToString
    13. End If
    14. End Function
    15. Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
    16. Throw New NotImplementedException()
    17. End Function
    18. End Class


    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Neu

    @Sascha: Mal wieder vielen Dank für die Hilfe. Der Converter klappt prima und gefällt mir sehr gut! Schön kurz und knapp. Auf diese Art der Lösung wär ich allerdings in den nächsten 10 Jahren noch nicht alleine gekommen. :)

    Zu dem ersten Lösungsvorschlag: Es wunderte mich auch schon, dass man für einen Tooltip extra einen Trigger mit angeben muss. Macht ja irgendwie keinen richtigen Sinn und ist vor allem bei Buttons (oder anderen Controls) wieder nicht nötig. Die Variante findet vielleicht zukünftig in Projekten mit wesentlich weniger Tabellen Einsatz.

    Scheibar findest Du 40 Spalten wohl etwas viel. :) Es handelt sich um 7 unterschiedliche DataGrids in verschiedenen Tabs. Aber trotzdem müssten ja nach meiner ursprünglichen Methode für jede Spalte mehrere Zeilen hinzugefügt werden. Da wär mein XAML ja explodiert. :) Und das schon bei der doch recht winzigen Dimension meines Projekts.

    Gestern konnte ich es nicht abwarten und habe mal kurz das beschriebene Konzept mit den Dictionarys und vielen Einzelstyles und Keys versucht. Hat auch geklappt, ist aber natürlich viel aufwändiger. Kann aber nich schaden das auch mal gemacht zu haben.

    Danke nochmal und Gruß

    eddi

    Neu

    eichseinet schrieb:

    Scheibar findest Du 40 Spalten wohl etwas viel. Es handelt sich um 7 unterschiedliche DataGrids in verschiedenen Tabs.

    OK, das geht dann ja wieder. Also keine 40 Spalten in einem DataGrid. OK. Aber mich persönlich stört das überhaupt nicht. Es gibt ja in VS das nette + bzw. - wo an die Zeilen aus/einblenden kann. Insofern schmälert dies nicht die Übersichtlichkeit des XAML.

    Grüße
    Sascha
    If _work = worktype.hard Then Me.Drink(Coffee)
    Seht euch auch meine Tutorialreihe <WPF Lernen/> an oder abonniert meinen YouTube Kanal.

    ## Bitte markiere einen Thread als "Erledigt" wenn deine Frage beantwortet wurde. ##

    Neu

    Ja klar, man kann es zuklappen. Aber trotzdem find ich es besser, wenn es nicht so übertrieben viel ist und das dann auch noch bloß für die Tooltips. Außerdem arbeite ich immer wieder auf 2 Rechnern an dem Projekt. Dann ist immer wieder alles aufgeklappt.

    Wie gesagt; die Methode mit dem Converter find ich sehr gut und übersichtlich.

    Gruß

    eddi

    Neu

    Und da ware sie wieder, meine 3 Probleme...
    Der Converter bringt leider eine Fehlermeldung, wenn er im 2. Tab aufgerufen wird. Im 1. Tab funktioniert ert mal alles. Öffnet man den 2. Tab mit der nächsten DataGrid, dann erscheint folgende Fehlermeldung.

    {"Fehler beim Auflösen der Überladung. Kein Public = kann mit diesen Argumenten aufgerufen werden: " & vbCrLf & " 'Public Shared Operator =(a As String, b As String) As Boolean':" & vbCrLf & " Der mit dem Argument übereinstimmende Parameter b kann nicht von MainWindow in String konvertieren.."} System.InvalidCastException

    Daraufhin habe ich in dem kleinen Testprojekt von gestern (das funktionierte ja) einfach einen Tab vor den funktionierenden eingefügt. Dann erscheint da die gleiche Meldung.
    Der Converter wird immer erst beim Öffnen des Tabs durchlaufen.

    Hat einer Rat?

    P.S. Ich lass es jetzt doch mit dem Converter. Den Fehler finde ich nicht und daher kommt jetzt doch ein StyleDictionary zum Einsatz.

    Gruß

    eddi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „eichseinet“ ()

    Neu

    Hast du Option Strict Off eingestellt?
    x.Key ist vom Typ String und DataContext ist vom Typ Object...

    VB.NET-Quellcode

    1. Return _tooltipKeyValuePairs.FirstOrDefault(Function(x) x.Key = DirectCast(value, DataGridColumnHeader).DataContext.ToString).Value

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VB1963“ ()

    Neu

    Wenn Option Strict nicht manuell auf on gestellt ist, dann ist off, oder? Wär bei mir also aus.
    Aber wird das nicht durch DirectCast gewandelt? Außerdem klappt der Converter solange das DataGrid im 1. Tab liegt. Fügt man in meinem Testprojekt nur einen weiteren Tab vorher ein, dann tritt auch schon der Fehler auf.

    Gruß

    eddi

    Neu

    Ja, hast recht. Wenn man es einschaltet markiert die Software die Zeile auch gleich als fehlerhaft. Hat jetzt etwas länger gedauert, weil nach der Änderung angeblich kein passendes Element (oder so) gefunden wurde. Hat aber alles gepasst. Erst nach dem Neustart von Visual Studio gings dann.

    Vielen Dank für deine Hilfe.

    Gruß

    eddi