Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Control template: how to create bindings

Tags:

c#

wpf

xaml

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}" ...>
like image 504
mHelpMe Avatar asked Dec 18 '15 10:12

mHelpMe


People also ask

How do I use template binding?

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.

What is control template?

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.

What is control template in WPF?

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.

What is content presenter in WPF?

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.

What is templatebinding in a control template?

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.

How do I bind a button to a template?

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 }

What is template binding in Salesforce?

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.

What is the syntax for a template binding?

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.


4 Answers

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.

like image 96
Mike Guthrie Avatar answered Oct 24 '22 00:10

Mike Guthrie


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.

like image 33
AnjumSKhan Avatar answered Oct 24 '22 01:10

AnjumSKhan


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>
like image 2
dontbyteme Avatar answered Oct 24 '22 00:10

dontbyteme


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.

like image 1
Himalaya Avatar answered Oct 24 '22 00:10

Himalaya