14

So, I have a datagrid that has different colour cells depending on the cell's value.

I also have a tooltip that displays some further information. This all works fine.

I, however, would like to alter the tooltip to show further information and also to be the same colour as the cell. So, I thought it would be wise to create a custom style for my tool tips. So, I have the below code.

<Style TargetType="ToolTip">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="ToolTip">
          <Border CornerRadius="15,15,15,15" 
                  BorderThickness="3,3,3,3" 
                  Background="#AA000000"  
                  BorderBrush="#99FFFFFF"
                  RenderTransformOrigin="0.5,0.5">
                   <Grid>
                     <Grid.RowDefinitions>
                       <RowDefinition Height="2*"/>
                       <RowDefinition/>
                       <RowDefinition/>
                     </Grid.RowDefinitions>
                    <TextBlock Grid.Row="0"/>
                      <TextBlock Grid.Row="1"/>
                      <TextBlock Grid.Row="2"/>
                   </Grid>
             </Border>
          </ControlTemplate>
       </Setter.Value>
    </Setter>
 </Style>

I have an object shown below that is bound to my datagrid. I want to bind the three properties to the three textboxes in my tooltip.

class MyTask
{
    public string Name;
    public int Code;
    public string Description;
}

In my DataGrid I do the following to bind my data to my datagrid

ItemsSource="{Binding TaskList}"

Then in the DataGridTextColumn I bind to a property like below

DataGridTextColumn Header="Code" Binding="{Binding Code}"

This makes sense to me. I am however at a loss to see how I use binding when creating my custom tooltip. I read that I can use templatebinding. I still don't understand how my tooltip will bind to my object of type MyTask in my xaml above?

Update - hopefully make my question clearer

I want to know how to create the bindings in my control template (for the 3 textboxes) and then in the main part of my code how I bind to these text boxes. I then would like to know how to create a binding for the background colour of my control template, I believe this is something to do with relativesource?

When I'm reading other examples (changing the Template Property) I see lines like below. I don't really understand why you have to do it? Is it a case of if you didn't right the line below you wouldn't be able to create a binding on the Padding property?

<Border Padding="{Binding Padding}" ...>
mHelpMe
  • 6,336
  • 24
  • 75
  • 150
  • Where is the "Code" property defined? Is it inside TaskList? If so, did you tried doing Binding="{Binding TaskList.Code}" ? Also, can you post your grid code? That would help. – jpgrassi Dec 18 '15 at 11:18
  • Yes TaskList is List. The binding for the datagrid is working. I was using that to say I understand how that works however I'm unsure how to use binding when changing the template of a control – mHelpMe Dec 18 '15 at 11:52
  • The easiest way is to go for a custom control and define dependency properties: http://stackoverflow.com/questions/11896619/custom-control-dependency-property-binding – Bart Dec 18 '15 at 12:22

4 Answers4

9

You don't need TemplateBindng, as that is used for setting up the resulting template object to layout based on dynamically using the properties of the implementing control. See this CodePlex article for a good example of when you'd need such functionality.

You simply need to set the bindings of your TextBlock elements within your ToolTip. You don't really need a Template at all in this case, except that since you are using the same ToolTip across all your column cells, it will help you out as you don't need to copy-paste the same code three times. You are after something similar to this article, Tooltip in DataGrid in WPF.

A solution which would work specifically to your case would be like:

<DataGrid Name="TestGrid1" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Name">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}">
                        <TextBlock.ToolTip>
                            <ToolTip />
                        </TextBlock.ToolTip>
                    </TextBlock>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Code">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Code}">
                        <TextBlock.ToolTip>
                            <ToolTip />
                        </TextBlock.ToolTip>
                    </TextBlock>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Description">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Description}">
                        <TextBlock.ToolTip>
                            <ToolTip />
                        </TextBlock.ToolTip>
                    </TextBlock>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
    <DataGrid.Resources>
        <Style TargetType="ToolTip">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ToolTip">
                        <Border CornerRadius="15,15,15,15" 
                                BorderThickness="3,3,3,3" 
                                Background="#AA000000"  
                                BorderBrush="#99FFFFFF"
                                RenderTransformOrigin="0.5,0.5">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="2*"/>
                                    <RowDefinition/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <TextBlock Grid.Row="0" Text="{Binding Name}"/>
                                <TextBlock Grid.Row="1" Text="{Binding Code}"/>
                                <TextBlock Grid.Row="2" Text="{Binding Description}"/>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.Resources>
</DataGrid>

You set the ToolTip property within the CellTemplate so that the resulting ToolTip that pops up has the same DataContext as the active row in the DataGrid. This way, you can simply do your property bindings as normal within your ToolTip ContentTemplate, since it has access to all the same properties as does your DataGrid for the row.

Mike Guthrie
  • 4,029
  • 2
  • 25
  • 48
  • Thanks very much. I had read those article but for some reason I didn't quite follow. However with your comments its a lot clearer! To get the background colour of the tooltip to be the same as the datagrid cell - would that be – mHelpMe Dec 21 '15 at 16:29
  • @mHelpMe Hmm... not sure off-hand. That one I'll have to experiment a bit to see if I can find. The easiest way would just be to add it as a property of `MyTask` as @dontbyteme recommended. If the color is based on the other values in `MyTask` that would also be the more reasonable place to put it. – Mike Guthrie Dec 21 '15 at 16:35
  • 1
    @mHelpMe I got it to work by setting the background of the `TextBlock` in the cell and binding to that (e.g., `` and ``). Still working for the proper binding to the grid cell itself. – Mike Guthrie Dec 21 '15 at 16:43
  • @mHelpMe How were you setting the cell background before? Or does the solution using the `TextBlock` background work well enough for you? – Mike Guthrie Dec 21 '15 at 17:28
4

To use underlying DataGridCell Background as ToolTip Background, bind your Border Background as Background="{Binding PlacementTarget.Background, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}" .

You are trying to show all the fields in the tooltip of a cell. That doesn't make sense. But still you can do that easily using

  1. PlacementTarget property, which gives you the underlying Visual element. ContextMenu, Popup too expose this property.

  2. PlacementTarget.DataContext will give you the underlying MyTask object.

  3. PlacementTarget.Content will give you the content of the corresponding DataGridCell, in your case it will be TextBlock.

So, if you want to show 3 fields in your cell's tooltip, below code will work for you using point number 2 above.

    <DataGrid.CellStyle>
    <Style TargetType="DataGridCell">
        <Setter Property="Background" Value="Tomato"/>
        <Setter Property="ToolTip">
            <Setter.Value>
                <ToolTip>
                    <ToolTip.Style>
                        <Style TargetType="ToolTip">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="ToolTip">
                                        <Border CornerRadius="15,15,15,15" 
                                                    BorderThickness="3,3,3,3" 
                                                    Background="{Binding PlacementTarget.Background, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}"  
                                                    BorderBrush="#99FFFFFF"
                                                    RenderTransformOrigin="0.5,0.5">
                                            <Grid>
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="2*"/>
                                                    <RowDefinition/>
                                                    <RowDefinition/>
                                                </Grid.RowDefinitions>
                                                <TextBlock Grid.Row="0" Text="{Binding PlacementTarget.DataContext.Name, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}" 
                                                        />
                                                <TextBlock Grid.Row="0" Text="{Binding PlacementTarget.DataContext.Code, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}" 
                                                        />
                                                <TextBlock Grid.Row="0" Text="{Binding PlacementTarget.DataContext.Description, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}" 
                                                        />
                                            </Grid>
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ToolTip.Style>

                </ToolTip>
            </Setter.Value>
        </Setter>
    </Style>
    </DataGrid.CellStyle>

And, if you want to show only corresponding cell's field in your cell's tooltip, then remove the remaining 2 textblocks, and use only one as :

<TextBlock Text="{Binding PlacementTarget.Content.Text, RelativeSource={RelativeSource AncestorType=ToolTip, Mode=FindAncestor}}" />

If you want to show all 3 fields, then apply the ToolTip to DataGridRow using DataGrid.RowStyle. No change in code would be needed.

AnjumSKhan
  • 9,647
  • 1
  • 26
  • 38
2

What about using a color property in MyTask?

class MyTask
{
    public string Name { get; set; }
    public int Code { get; set; }
    public string Description { get; set; }
    public SolidColorBrush Color { get; set; }
}

And binding to the color property:

 <Style TargetType="ToolTip">
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="HasDropShadow" Value="True"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ToolTip">
                <Border Name="Border" Background="{Binding Color}" BorderBrush="{StaticResource SolidBorderBrush}"  BorderThickness="1"  Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                        <TextBlock Text="{Binding Code}" />
                        <TextBlock Text="{Binding Description}" />
                    </StackPanel>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
dontbyteme
  • 1,221
  • 1
  • 11
  • 23
1

Why don't you go for DataTemplate of tool tip like give it's a key and apply it in your cell tool tip style.

<Style TargetType="ToolTip" x:Key="ToolTipStyle">
  <Setter Property="ContentTemplate">
    <Setter.Value>
      <DataTemplate TargetType="ToolTip">
          <Border CornerRadius="15,15,15,15" 
                  BorderThickness="3,3,3,3" 
                  Background="#AA000000"  
                  BorderBrush="#99FFFFFF"
                  RenderTransformOrigin="0.5,0.5">
                   <Grid>
                     <Grid.RowDefinitions>
                       <RowDefinition Height="2*"/>
                       <RowDefinition/>
                       <RowDefinition/>
                     </Grid.RowDefinitions>
                    <TextBlock Grid.Row="0"/>
                      <TextBlock Grid.Row="1"/>
                      <TextBlock Grid.Row="2"/>
                   </Grid>
             </Border>
          </DataTemplate>
       </Setter.Value>
    </Setter>
 </Style>

Now, you can bind your property to textblock too.

Himalaya
  • 81
  • 7