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}" ...>
To modify the visual tree generated by a template to reflect the control's property values, you must use template bindings. A template binding is a special type of data binding that allows you to reference the parent control, read its properties and apply their values. In some cases, you can use the values directly.
The ControlTemplate allows you to specify the visual structure of a control. The control author can define the default ControlTemplate and the application author can override the ControlTemplate to reconstruct the visual structure of the control.
The ControlTemplate contains the tree of elements that define the desired look. After you define a ControlTemplate you can attach it to any Control or Page by setting it's TemplateProperty. In this example I am also showing you how to use Triggers with ControlTemplate.
In WPF Content Presenter is a control that displays a single piece of content. In WPF Content Presenter is a control that displays a single piece of content. CONTENT PRESENTER: Content Presenter in WPF is used inside control templates, as well as inside the root application markup.
A TemplateBinding is a special binding that links the value of a property in a control template to the value of some other exposed property on the templated control. TemplateBinding can only be used within a ControlTemplate definition in XAML. See TemplateBinding markup extension for more info.
You could use the Button.Tag property, for example, and then bind to that in your template. Or you could define your own control: public class ImageButton : Button { // add Source dependency property a la Image }
A template binding is a special type of data binding that allows you to reference the parent control, read its properties and apply their values. In some cases, you can use the values directly.
The syntax for a template binding is similar to that of a simple data binding. Use the TemplateBinding markup and the name of the source property, contained within a pair of braces {}. To demonstrate, let's create a template for the progress bar and add some template bindings.
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.
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
PlacementTarget
property, which gives you the underlying Visual element. ContextMenu, Popup too expose this property.
PlacementTarget.DataContext
will give you the underlying MyTask object.
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.
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>
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With