I have created a style for a “required field” label which should place a red asterisk “*” in front of the label. Here is my xaml taken from the Application.Resources section of my WPF application:
<Style TargetType="Label" x:Key="RequiredField">
<Setter Property="Margin" Value="0,0,5,0" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Content">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="*" Foreground="Red" FontSize="10"/>
<TextBlock Text="{Binding}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The xaml in my view uses the resource like this:
<Label Grid.Row="1" Grid.Column="0" Style="{StaticResource RequiredField}" Content="Name:"/>
Annoyingly it doesn’t appear to modify the label. Can anyone tell me what I’ve done wrong?
Well your style seems to be wrong. I would try it that way.
<Style TargetType="Label" x:Key="RequiredField">
<Setter Property="Margin" Value="0,0,5,0" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="*" Foreground="Red" FontSize="10"/>
<TextBlock Text="{TemplateBinding Content}" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This should do the trick, but it's totally untested.
The template is assigned to the Content property. That is wrong.
Instead it can be assigned to the Template property but in this case it might be better to use the Validation.ErrorTemplate property because it is meant for validation adorners.
From this article:
<ControlTemplate x:Key="TextBoxErrorTemplate">
<StackPanel>
<StackPanel Orientation="Horizontal">
<Image Height="16" Margin="0,0,5,0"
Source="Assets/warning_48.png"/>
<AdornedElementPlaceholder x:Name="Holder"/>
</StackPanel>
<Label Foreground="Red" Content="{Binding ElementName=Holder,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
</StackPanel>
</ControlTemplate>
<TextBox x:Name="Box"
Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
Related
I've got the following problem. I have a DataGrid with a DataGridTemplateColumn and I want to display the text of a cell with a popup (because it can be trimmed).
This is my xaml code:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Description}"
TextTrimming="CharacterEllipsis">
<TextBlock.ToolTip>
<ToolTip Style="{StaticResource ToolTipBrowserDescription}" ToolTip="test"/>
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Style:
<Style TargetType="{x:Type ToolTip}" x:Key="ToolTipBrowserDescription">
<Setter Property="DataContext" Value="{Binding RelativeSource={x:Static RelativeSource.Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}">
<Border BorderBrush="{StaticResource HT_Background_DarkGrey}" Background="{StaticResource HT_Background_LightGrey3}" BorderThickness="1">
<TextBlock Text="{Binding ToolTip}" FontWeight="Bold" TextWrapping="Wrap" Margin="5" MinWidth="50" MaxWidth="{TemplateBinding MaxWidth}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But when I'm setting the ToolTip Property from "test" to "{Binding Description}" the ToolTip (which is shown) is empty.
Has anyone the solution for me. I'm stuck for about 2h..
This should do the trick.
ToolTipStyle:
<Style x:Key="ToolTipBrowserDescription"
TargetType="{x:Type ToolTip}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}">
<Border BorderBrush="{StaticResource HT_Background_DarkGrey}"
Background="{StaticResource HT_Background_LightGrey3}"
BorderThickness="1">
<TextBlock Text="{TemplateBinding Content}"
FontWeight="Bold"
TextWrapping="Wrap"
Margin="5"
MinWidth="50"
MaxWidth="{TemplateBinding MaxWidth}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
TextBlock:
<TextBlock Text="{Binding Description}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Style="{StaticResource ToolTipBrowserDescription}"
Content="{Binding Description}"/>
</Setter.Value>
</Setter>
</Style>
</TextBlock.Style>
</TextBlock>
You should Template-Bind to content, instead to ToolTip of the ToolTip
I am having a strange issue. I am not sure if this is a bug, or if I am simply misunderstanding something as I am fairly new to WPF (Probably the latter).
In my project, I have a ListView that displays items in a similar fashion to that seen of Windows Explorer using Icon view. I have outlined a control template that consists of a an Image element, and a TextBlock element below it. My goal is to adjust the maximum height of the TextBlock when the ListViewItem is selected. This is so the name of the Items will adjust from being trimmed with an ellipsis to showing the full name of the item.
When the item is selected however, instead of adjusting the maximum height of only the selected item's TextBlock, it adjusts all TextBlocks for each item whether it is actively selected or not.
I have researched for an answer, but have not found anything similar to this particular issue. This link is a similar concept, but without my problem.
WPF - ListView Item on Selected change Font size
Some of my other methods have consisted of one ControlTemplate with triggers for the style changes, or ItemContainerStyle instead of explicitly a ControlTemplate, which all seemed to give the same undesired result.
How can I achieve this functionality? Is it possible with ControlTemplate?
Here is some of my XAML code:
ListView
<ListView x:Name="ItemViewer">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="10"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Margin" Value="10"/>
<Setter Property="Template" Value="{StaticResource ListViewItemNormal}"/>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"/>
<Condition Property="Selector.IsSelectionActive" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Template" Value="{StaticResource ListViewItemSelected}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
ControlTemplates
<ControlTemplate x:Key="ListViewItemNormal" TargetType="{x:Type ListViewItem}">
<Border x:Name="ItemBoxBorder" Background="Transparent">
<Grid HorizontalAlignment="Left" MinHeight="90"
Margin="5"
MaxWidth="90"
Width="90"
x:Name="ItemBox">
<StackPanel>
<Image HorizontalAlignment="Center"
VerticalAlignment="Top"
Source="{StaticResource NewImage}"
Width="64" Height="64"/>
<TextBlock x:Name="ItemDescription"
Text="{Binding Path=Name}"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
TextWrapping="Wrap"
MaxWidth="90"
MaxHeight="30"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
<Grid.ToolTip>
<ToolTip Content="{Binding Path=Name}"/>
</Grid.ToolTip>
</Grid>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="False"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="ItemBoxBorder" Property="Background" Value="{StaticResource HighlightMouseHoverColorBrush}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ListViewItemSelected" TargetType="{x:Type ListViewItem}">
<Border x:Name="ItemBoxBorder" Background="{StaticResource SelectedItemBrush}"
BorderBrush="{StaticResource HighlightBorderColorBrush}"
BorderThickness="1">
<Grid HorizontalAlignment="Left" MinHeight="90"
Margin="5"
MaxWidth="90"
Width="90"
x:Name="ItemBox">
<StackPanel>
<Image HorizontalAlignment="Center"
VerticalAlignment="Top"
Source="{StaticResource NewImage}"
Width="64" Height="64"/>
<TextBlock x:Name="ItemDescription"
Text="{Binding Path=Name}"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
TextWrapping="Wrap"
MaxWidth="90"
MaxHeight="125"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
<Grid.ToolTip>
<ToolTip Content="{Binding Path=Name}"/>
</Grid.ToolTip>
</Grid>
</Border>
</ControlTemplate>
EDIT
Here is an example of the issue with ms_dos's implementation.
This image shows I have the item with a short description selected. This is the height all items should remain if they are not selected.
In this image, you'll see the item with the long description is selected. However, both items extend their height, but only the selected one should grow.
You don't need two separate control templates for this. Just take the ItemContainerStyle property of the ListView and use a control template like this:
<ListView x:Name="ItemViewer">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="10" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border x:Name="ItemBoxBorder"
Background="Green"
BorderThickness="1"
VerticalAlignment="Top">
<Grid HorizontalAlignment="Left"
MinHeight="90"
Margin="5"
MaxWidth="90"
Width="90"
x:Name="ItemBox">
<StackPanel>
<Image HorizontalAlignment="Center"
VerticalAlignment="Top"
Width="64"
Height="64" />
<TextBlock x:Name="ItemDescription"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
TextWrapping="Wrap"
Text="{Binding}"
MaxWidth="90"
MaxHeight="125"
TextTrimming="CharacterEllipsis" />
</StackPanel>
<Grid.ToolTip>
<ToolTip Content="{Binding Path=Name}" />
</Grid.ToolTip>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="true">
<Setter TargetName="ItemBoxBorder"
Property="Background"
Value="Red" />
<Setter TargetName="ItemDescription"
Property="TextElement.FontSize"
Value="20" />
<Setter TargetName="ItemBoxBorder"
Property="Height"
Value="135" />
</Trigger>
<Trigger Property="IsSelected"
Value="false">
<Setter TargetName="ItemBoxBorder"
Property="Height"
Value="90" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Take a look at the ControlTemplate.Triggers section. Basically you use the Trigger property to control which property the trigger should handle... in our case the IsSelected from the ListView. And with the Setter you define the property and the value for the changes of the ListViewItem control. The TargetName of the Setter refers to the x:Name of the control which you define in the ControlTemplate section.
I hope this example helps you with your problem!
Greets
ms_dos
I have a custom Validation.ErrorTemplate and for some reason, WPF displays both my custom error template and the default one. They both show the same error as expected, however I don't want to display the default ErrorTemplate.
My code:
<Style TargetType="TextBox" x:Key="MyTextBox">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border BorderBrush="red" BorderThickness="1" Background="#11FF0000" IsHitTestVisible="False" x:Name="errorBorder"/>
<AdornedElementPlaceholder x:Name="placeholder" />
<Popup AllowsTransparency="True" HorizontalAlignment="Right" HorizontalOffset="0" VerticalOffset="0" PopupAnimation="Fade" Placement="Right"
PlacementTarget="{Binding ElementName=errorBorder}" IsOpen="{Binding ElementName=placeholder, Path=AdornedElement.IsFocused, Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<Polygon VerticalAlignment="Center" Points="0,4,4,4" Fill="red" Stretch="Fill" Stroke="red"
StrokeThickness="2" />
<Border Background="red" CornerRadius="0" Padding="4">
<TextBlock HorizontalAlignment="Center" Foreground="white" FontWeight="Bold" Margin="2,0,0,0"
Text="{Binding ElementName=placeholder, Path=AdornedElement.ToolTip, Mode=OneWay}" />
</Border>
</StackPanel>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
And this
<Style TargetType="TextBox" BasedOn="{StaticResource MyTextBox}"/>
I'd like to know if anyone knows why WPF displays both my error template and the default one.
EDIT
http://i58.tinypic.com/a14k6q.png - the picture with both errors showing
It is because you defined ErrorTemplate and also defiend a Validation.HasError trigger in your style, you could use one of them. If you want to use the ErrorTemplate you need to remove the trigger, and change the Text binding to "Path=AdornedElement.Validation.Errors).CurrentItem.ErrorContent" then you will just see the result from ErrorTemplate:
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border/>
<AdornedElementPlaceholder x:Name="placeholder" />
<Popup>
<StackPanel>
<Polygon/>
<Border>
<TextBlock Text="{Binding ElementName=placeholder,
Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent,
Mode=OneWay}" />
</Border>
</StackPanel>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
In our WPF application we have a common control template which we use to display errors in a consistent way
<ResourceDictionary>
<ControlTemplate x:Key="ErrorTemplate">
<Border BorderThickness="1" BorderBrush="Red">
<AdornedElementPlaceholder />
</Border>
</ControlTemplate>
</ResourceDictionary>
Elsewhere in our application when a control might display an error we set the ErrorTemplate like so
<TextBox Validation.ErrorTemplate="{DynamicResource ErrorTemplate}" />
I now want to display a tool tip in this error template, however setting the tooltip property on the border doesn't help that much as the tooltip only displays when the user mouses over the 1px wide border, not the control itself which is in error.
I know that I can set the tooltip in a style, however this error template is applied to many different controls (combo boxes etc...) and many of these controls also use styles which are independent from my error template - I really want to be able to apply my error template in a generic way to any control.
Is there any way that I can set a tooltip in my ErrorTemplate?
I have a style defined. I have IDataErrorInfo on my object (Customer) which does the validation for the property(LastName) which is databound to a text box for example. Here's my style:
<Style x:Key="ValidationTextBox" TargetType="{x:Type Control}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,2,40,2"/>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Border Background="#B22222" DockPanel.Dock="Right" Margin="5,0,0,0" Width="20" Height="20" CornerRadius="10"
ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock Text="!" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" Foreground="White"/>
</Border>
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center">
<Border BorderBrush="#B22222" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style
<TextBox Style="{StaticResource ValidationTextBox}" Text="{Binding Path=Customer.LastName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnTargetUpdated=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" />
As I stated in my answer here you can:
<ControlTemplate x:Key="ErrorTemplate">
<Border BorderThickness="1" BorderBrush="Red"
Background="Transparent"
ToolTip="{Binding Path=/ErrorContent}">
<AdornedElementPlaceholder />
</Border>
</ControlTemplate>
I'm sorry I didn't have time yesterday...Would you try below and see if this is what you are after, please?
<Style x:Key="ValidationTextBox2" TargetType="{x:Type Control}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="Red" BorderThickness="2">
<DockPanel LastChildFill="True" ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" Background="Transparent">
<TextBlock />
<AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center">
</AdornedElementPlaceholder>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I have the following xaml for displaying files. If the file exists on the local machine, it's a clickable hyperlink, otherwise just a normal textblock.
<TextBlock Visibility="{Binding FileName, Converter={StaticResource fileExistsConverter}}" Grid.Column="2" TextDecorations="Underline" Margin="5,0,0,0" Foreground="Black" Text="{Binding FileName}" />
<TextBlock Margin="5,0,0,0" Grid.Column="2" Visibility="{Binding FileName, Converter={StaticResource fileDoesntExistConverter}}">
<Hyperlink Click="Hyperlink_Click_1">
<TextBlock Text="{Binding FileName}" />
</Hyperlink>
</TextBlock>
This works on page load, but doesn't update when the window is open when for example one of the listed files is downloaded. How would I go about triggering a refresh so the XAML can swap the styles?
resources :
<Style x:Key="SwapTemplateStyle" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<TextBlock />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsExist}" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Hyperlink>
<TextBlock />
</Hyperlink>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
in your view :
<ContentControl Style="{StaticResource SwapTemplateStyle}" />