I just need a simple WPF ToolTip Style that displays multiple lines - wpf

Due to all the noise about fancy, super, huge, and blah, blah, blah, tooltips, I cannot find the answer.
I just need a simple style that sets TextWrapping="Wrap" and allows me to set a width.
One that duplicates the existing / default style, but just word wraps.

<Window.Resources>
<Style TargetType="{x:Type ToolTip}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock TextWrapping="Wrap" Text="{Binding}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Rectangle Width="100" Height="100" Fill="Red">
<Rectangle.ToolTip>
<ToolTip Width="100">
This is some text with text wrapping.
</ToolTip>
</Rectangle.ToolTip>
</Rectangle>
</Grid>
This example is assuming you want to be able to set the width on a per-usage basis. If you want to set it as part of the style, add it to the TextBlock element.

This style prevents a tooltip from popping up on empty strings.
<Style TargetType="ToolTip">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<TextBlock Text="{TemplateBinding Content}"
MaxWidth="400"
TextWrapping="Wrap"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Content" Value="">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
Or using ContentTemplate:
<Style TargetType="{x:Type ToolTip}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding}"
MaxWidth="400"
TextWrapping='Wrap' />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Content" Value="">
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>

If you just want to get the effects below, have a read at this post.

Related

How to set Button Height dynamically in RowDetails RowHeaderTemplate

I have a datagrid with a Deails-View which shows another datagrid. This second grid is normally not shown. In the row header there is a button with a left arrow, when this is clicked, the details-grid is shown and the arrow changes to a down-arrow. This all works perfectly, but there is only a "small area" in the rowheader which accepts clicks. This is the code of my RowHeader-Template:
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<Button Click="DataGridRowHeader_Button_Click" Cursor="Hand" HorizontalAlignment="Center" Width="40" >
<Button.Style>
<Style TargetType="Button">
<Style.Setters>
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid >
<Border Background="Chartreuse" BorderBrush="Black" BorderThickness="5"></Border>
<Path Fill="Blue" Data="M 0,0 14,7 0,14 Z" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow}},Path=DetailsVisibility}" Value="Visible">
<Setter Property="Background" Value="Salmon" />
<Setter Property="Height" Value="125" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}" >
<Grid >
<Border Background="LightCoral" BorderBrush="Black" BorderThickness="1" />
<Path Fill="Blue" Data="M 0,0 14,0 7,14 Z" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
The line with
Setter Property = "Height" Value="125"
expands the button
but the button does not fit into the row header. With A small value, the button shrinks, and with a high button, the row header expands unnecessarily.
I tried to bind the Heigth-value to some parameters, e. g.
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRowDetailsEventArgs}}, Path=DetailsElement.ActualHeight}" />
(DataGridRowDetailsEventArgs captures the correct height-value when I look in code-behind:
private void dg_RowDetailsVisibilityChanged(object sender, DataGridRowDetailsEventArgs e)
{
Trace.WriteLine(e.DetailsElement.ActualHeight);
}
). Using
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRowDetails}}, Path=ActualHeight}" />
does not work either, the RowHeader is always expanded to a value which seems to be the height of the whole Master-Datagrid.
Any ideas how I can size the button correctly?
(Sorry for the colors, they are used only to see the different parts of the UI).
Hucky
I think your problem lies within the ControlTemplate of the DataGridRowHeader where you can't properly align content (in your case your Button)
Instead of overriding the ContentTemplate every single time with full Xaml I tried another approach by using a MarkupExtension(AlignmentControlTemplateExtension), which does the necessary steps for me (clone and adjust the default ControlTemplate), so that I only have to do something like this
<Setter Property="Template" Value="{AlignmentControlTemplate Type={x:Type WhatEverType}}" />
To solve your problem you have to do only some few steps
Set the DataGridRowHeader ControlTemplate
<DataGrid.RowHeaderStyle>
<Style TargetType="DataGridRowHeader">
<Setter Property="Template" Value="{stackoverflow:AlignmentControlTemplate Type={x:Type DataGridRowHeader}}"></Setter>
</Style>
</DataGrid.RowHeaderStyle>
Set VerticalContentAlignment and/or HorizontalContentAlignment however you like it (in your case VerticalContentAlignment=Stretch)
<DataGrid.RowHeaderStyle>
<Style TargetType="DataGridRowHeader">
<Setter Property="VerticalContentAlignment" Value="Stretch"></Setter>
<Setter Property="Template" Value="{stackoverflow:AlignmentControlTemplate Type={x:Type DataGridRowHeader}}"></Setter>
</Style>
</DataGrid.RowHeaderStyle>
Some adjustments in your Style.Triggers
Replace
<Setter Property="Height" Value="125" />
with
<Setter Property="VerticalAlignment" Value="Stretch" />
Edit Final Result
<DataGrid>
<!-- Step 1 -->
<DataGrid.RowHeaderStyle>
<Style TargetType="DataGridRowHeader">
<Setter Property="VerticalContentAlignment" Value="Stretch"></Setter> <!-- Step 2 -->
<Setter Property="Template" Value="{stackoverflow:AlignmentControlTemplate Type={x:Type DataGridRowHeader}}"></Setter>
</Style>
</DataGrid.RowHeaderStyle>
<!-- /Step 1 -->
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<Button Click="DataGridRowHeader_Button_Click" Cursor="Hand" HorizontalAlignment="Center" Width="40" >
<Button.Style>
<Style TargetType="Button">
<Style.Setters>
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid >
<Border Background="Chartreuse" BorderBrush="Black" BorderThickness="5"></Border>
<Path Fill="Blue" Data="M 0,0 14,7 0,14 Z" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGridRow}},Path=DetailsVisibility}" Value="Visible">
<Setter Property="Background" Value="Salmon" />
<Setter Property="VerticalAlignment" Value="Stretch" /> <!-- Step 3 -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}" >
<Grid >
<Border Background="LightCoral" BorderBrush="Black" BorderThickness="1" />
<Path Fill="Blue" Data="M 0,0 14,0 7,14 Z" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
...
</DataGrid>

Border per column header

I want to create a table on wpf that each column header has a round corner this is what i got so far:
as you can see, i have the desired outcome with a little un desired outcome.
the undesired out come is that the all data grid header itself (not the columns) is getting the same border, i need to make it transparent, how can i do that?
this is the part of the style:
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="SeparatorBrush" Value="Transparent"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border CornerRadius="5 5 0 0" BorderThickness="1" BorderBrush="Black">
<TextBlock Text="{Binding }"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
for some reasons, DataGrid has a blank DataGridColumnHeader in its template. that blank columns doesn't have DataContext value (null). So change border brush to transparent in a DataTrigger:
<ControlTemplate>
<Grid>
<Border CornerRadius="5 5 0 0" BorderThickness="1" >
<TextBlock Text="{Binding}"/>
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="Black"/>
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter Property="BorderBrush" Value="Transparent"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</Grid>
</ControlTemplate>
improved version, which uses ContentPresenter in header template and test Content in a trigger
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Border CornerRadius="5 5 0 0" BorderThickness="1" >
<ContentPresenter/>
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="Black"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}" Value="{x:Null}">
<Setter Property="BorderBrush" Value="Transparent"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</Grid>
</ControlTemplate>
header is not necessary a text, e.g.:
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Name}">
<DataGridTextColumn.Header>
<Border Background="Cyan">
<TextBlock Text="NAME" Margin="5"/>
</Border>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>

How do I add different icons to treeview items in a wpf application using xaml?

I have a treeview which has been populated using a dataset. Now I need to add different icons to the treeview nodes. How do I add them using xaml?
You need to add a custom template for the TreeViewItem like this:
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Tag="{Binding}" />
<Image Source="{Binding Converter={StaticResource CustomImagePathConvertor}}" />
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
You can change Image Path and use Template to implement it:
<ToggleButton x:Name="Expander" ClickMode="Press">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid Height="16" Width="16">
<Image x:Name="imgBkg" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Source" TargetName="imgBkg" Value="/XXXX;component/YourImage.png"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ToggleButton.Style>
</ToggleButton>

How to Clear Triggered Control Template

I am trying to achieve the "hint text" functionality for a TextBox in WPF. I can set the default text fine, but the problem comes when I want the control to return its appearance to a normal TextBox. Here is the trigger I have so far:
Trigger A
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBox>
<TextBox.Background>
<VisualBrush AlignmentX="Left" AlignmentY="Center" Stretch="UniformToFill">
<VisualBrush.Visual>
<Label Content="{TemplateBinding TextBox.Tag}" Background="White"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Background>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
This sets the Background to a VisualBrush when the Text property is empty. What I need to do is clear this ControlTemplate when the user selects the TextBox to input text.
Here is what I tried:
Trigger B
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBox/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
These two don't work together. I tested each by changing the Background colors. If I comment out either one, they will each work. If both are uncommented, Trigger A works and B is never seen. How can I remove/overwrite Trigger A?
I know that the functionality of these templates is supposed to clear when the trigger condition is no longer met, but for example, Trigger A's setting will not go away when I enter text into the TextBox like it should. Like the Text property is still String.Empty or something.
So what am I missing?
EDIT:
Here is the whole style (there's not much more to it):
<UserControl.Resources>
<Style TargetType="TextBox" x:Key="FormsTextBox">
<Setter Property="Width" Value="45"/>
<Setter Property="Margin" Value="3 2 3 2"/>
<Style.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<TextBox>
<TextBox.Background>
<VisualBrush AlignmentX="Left" AlignmentY="Center" Stretch="UniformToFill">
<VisualBrush.Visual>
<Label Content="{TemplateBinding TextBox.Tag}" Background="White" Width="45"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Background>
</TextBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
I cannot see whole template but this looks a bit overcomplicated. I assume you're trying to achieve watermark text. For hint use box standard ToolTip property, which by default will display your text in a popup when hover your TextBox but this behaviour can be disabled and ToolTip property reused. You can either create reusable Style - which I prefer - for TextBox, something like this:
<Window ...>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<Style TargetType="{x:Type TextBox}" x:Key="WatermarkTextBoxStyle">
<Setter Property="ToolTipService.IsEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
BorderThickness="1"
BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}">
<Grid>
<TextBlock Margin="5,0,0,0"
Text="{TemplateBinding ToolTip}"
Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text.IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}"
Opacity="0.5"/>
<ScrollViewer Name="PART_ContentHost"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<TextBox ToolTip="watermark text" Style="{StaticResource WatermarkTextBoxStyle}"/>
</Window>
or, if it's a one-off thing, then do you can do something like this without any Style or Template:
<Grid Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
<TextBlock Margin="5,0,0,0"
Text="watermark text"
Opacity="0.5"
Visibility="{Binding ElementName=myTextBox, Path=Text.IsEmpty, Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBox Name="myTextBox" Background="Transparent" />
</Grid>

WPF Style Binding to Base Style

i have a base style and a style in wpf.
the base style is:
<Style x:Key="BaseTextBox" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#DDFFDD" />
<Setter Property="MinWidth" Value="75" />
<Setter Property="behaviors:OCCInteraction.Triggers" Value="{StaticResource ResourceKey=validationTrigger}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Background" Value="#FFDDDD"/>
<Setter Property="ToolTip" Value="{Binding Path=(Validation.Errors)[0].ErrorContent, RelativeSource={x:Static RelativeSource.Self}}" />
</Trigger>
</Style.Triggers>
</Style>
And the the specific style is:
<Style x:Key="EditableTextBox" TargetType="{x:Type TextBox}" BasedOn="{StaticResource ResourceKey=BaseTextBox}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Red" BorderThickness="1" Padding="0" Margin="0">
<AdornedElementPlaceholder Margin="0"/>
</Border>
<TextBlock Text="test" />
<Image Style="{StaticResource ResourceKey=WarningImage}"/>
<TextBlock Text="{Binding Path=(Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource Mode=Self,AncestorLevel=2}}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now i want to add the Validation Error Text to a textblock next to the image. But the Same Binding Path doesn't work. I've tried diferent bindings, but I can't figure out how to access the same binding like on the base style.
Thanks for help :)
Have you tried it without the AncestorLevel? You should be the same object.
You cannot use Mode=Self and AncestorLevel properties. Just use Mode=Self.
Ancestor level is used when you try to reach parent of that control in visual tree.

Resources