Search code examples
wpfvb.netbindingtooltip

WPF DataGridCell Styling - Binding for Tooltips on multiple columns


I have a DataGrid that has an unknown number of columns. From the screenshot you will see there are 3 EF columns:

enter image description here

What you cannot see is that each EF column has other columns that are hidden that holds other information about its respective EF column. For example, There is a hidden column before EF1 called 1Status (which is used to conditionally format the cell backgrounds based on its value), and another hidden column named 1AssMeth) which holds the text to appear in the tooltip. Ergo - For each EF[X] column there are the respective XStatus & XAssMeth.

As you can see, I have the conditional background colours working.

The background colors are handled using a ValueConverter and are implemented with the following Resource:

<Window.Resources>
    <ResourceDictionary>

        <local:PercVerifiedConverter x:Key="PercVerifiedConverter" />
        <Style x:Key="PercVerified" TargetType="{x:Type DataGridCell}" >
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource PercVerifiedConverter}}" Value="Red">
                    <Setter Property="Background">
                        <Setter.Value>
                            <LinearGradientBrush>
                                <GradientStop Color="DarkRed" Offset="0"/>
                                <GradientStop Color="White" Offset="1"/>
                            </LinearGradientBrush>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Foreground" Value="White"></Setter>
                    <Setter Property="Margin" Value="0"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource PercVerifiedConverter}}" Value="Green">
                    <Setter Property="Background">
                        <Setter.Value>
                            <LinearGradientBrush>
                                <GradientStop Color="DarkGreen" Offset="0"/>
                                <GradientStop Color="White" Offset="1"/>
                            </LinearGradientBrush>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Foreground" Value="White"></Setter>
                    <Setter Property="Margin" Value="0"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource PercVerifiedConverter}}" Value="Orange">
                    <Setter Property="Background">
                        <Setter.Value>
                            <LinearGradientBrush>
                                <GradientStop Color="DarkOrange" Offset="0"/>
                                <GradientStop Color="White" Offset="1"/>
                            </LinearGradientBrush>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Foreground" Value="White"></Setter>
                    <Setter Property="Margin" Value="0"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</Window.Resources>

So this all works as far as the background color works... However I wish to also add a Tooltip to the style to return the value in the respective XAssMeth column. So, to get things rolling I did this to the Style above...

        <local:PercVerifiedConverter x:Key="PercVerifiedConverter" />
        <Style x:Key="PercVerified" TargetType="{x:Type DataGridCell}" >

            <Setter Property="ToolTip" Value="{Binding 1AssMeth}" />

            <Style.Triggers> .....

Which as you might imagine returns a Tooltip as expected, but every column has the same tooltip - the value in the 1AssMeth column.

Hover over the first row in EF1 and this tooltip appears

Then hover over the first row of any subsequent columns and the same tooltip text appears.

I would expect this behavior so am happy about that. What I need to know is how I might go about applying additional binding to the EF[X] columns so I get the correct Tooltip Text from the corresponding XAssMeth column - without loosing the functionality of my Background colour styling.

I can supply more information on the converter or anything else if that might help - but i'm hoping it is something simple? i.e. do I need another converter to get the correct corresponding Column Header XAssMeth or anything like that? If so then an example would be amazing!

P.s. I will be looking to expand on the Tooltip to make something customized - so if anyone is able to throw that into the mix as well, would be great!


Solution

  • To do this with a converter, like the DataTriggers are using:

    <local:PercVerifiedConverter x:Key="PercVerifiedConverter" />
    <local:TooltipConverter x:Key="TooltipConverter" />
    <Style x:Key="PercVerified" TargetType="{x:Type DataGridCell}" >
    
            <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource TooltipConverter}}" />
    
        <Style.Triggers>...
    

    The VB for the the converter:

    Public Class TooltipConverter
        Implements IValueConverter
    
        Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
            Convert = Nothing
            Dim cell As DataGridCell
            Dim dc As System.Data.DataRowView
    
            ' Get the DataGridCell passed in
            cell = TryCast(value, DataGridCell)
            If IsNothing(cell) Then Exit Function
    
            ' Get the cell's DataContext as our data class
            dc = TryCast(cell.DataContext, System.Data.DataRowView)
            If IsNothing(dc) Then Exit Function
    
            ' Get the cell's column - need it for the binding
            Dim tc As DataGridTextColumn ' Assuming your cells are DataGridTextColumns
            tc = TryCast(cell.Column, DataGridTextColumn)
            If IsNothing(tc) Then Exit Function
    
            ' Get the column's binding
            Dim b As Binding
            b = TryCast(tc.Binding, System.Windows.Data.Binding)
            If IsNothing(b) Then Exit Function
    
            ' Get the path off the binding
            Dim path As String
            path = b.Path.Path ' Name of the property this column is bound to - 1AssMeth, EF1, etc...
    
            ' If one of the "EF" properties, convert path to the appropriate "AssMeth" path
            If path.Contains("EF") Then
                Dim pvNum = path.Replace("EF", String.Empty) ' EF1 becomes 1
                path = pvNum + "AssMeth" ' path is now 1AssMeth
            End If
            If path.Contains("AssMeth") Then
                Convert = dc(path)
            End If
        End Function
    
        Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
            Throw New NotImplementedException()
        End Function
    End Class
    

    EDIT: To customize the tooltip, update your style to something like this:

    <Style x:Key="PercVerified" TargetType="{x:Type DataGridCell}" >
        <Style.Resources>
            <Style x:Key="{x:Type ToolTip}" TargetType="{x:Type ToolTip}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border Background="Beige" BorderBrush="Navy" BorderThickness="2">
                                <StackPanel Width="400" Height="200">
                                    <TextBlock Background="Bisque" Foreground="Maroon" Text="ToolTip Header" Margin="10" HorizontalAlignment="Stretch" />
                                    <TextBlock Text="My tooltip text is:" />
                                    <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}" Background="DarkBlue" Foreground="White" Margin="25" />
                                    <TextBlock Text="Something else could go here." />
                                </StackPanel>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Style.Resources>
        <Style.Setters>
            <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource TooltipConverter}}" />
        </Style.Setters>
        <Style.Triggers>...