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>
Related
So this is my XAML and for some reason it's not changing colors on mouseover, I added the triggers for it and I thought that would do it, when I hover over the button its not doing anything at all, why is that?
<Button Click="ButtonBase_OnClick" Margin="10,0,0,0" Style="{DynamicResource RoundedButtonStyle}" Width="100" Height="30" HorizontalAlignment="Left">
<Grid>
<Image IsHitTestVisible="False" Height="15" Width="15" VerticalAlignment="Center" HorizontalAlignment="Left" Source="Resources/addButton.png" />
<TextBlock IsHitTestVisible="False" Margin="20,0,0,1" VerticalAlignment="Center" Foreground="#9e9e9e">Add Product</TextBlock>
</Grid>
</Button>
<Window.Resources>
<Style x:Key="RoundedButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="5" Background="#2d2d30" BorderThickness="1" Padding="2">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Its not changing because you modified the control template of Button to:
<Border CornerRadius="5" Background="#2d2d30" BorderThickness="1" Padding="2"
Note the hard-coded background color. No matter what you do to the button's Background property it won't take effect since its not used. If you want to use that property in your template you need a TemplateBinding:
Background="{TemplateBinding Background}"
Then in the style set the default to your original value.
<Setter Property="Background" Value="#2d2d30"/>
I want to have a button with round edge grid and set disable button color to gray, green otherwise. Attached snippet of code. I don't know how to change the default. If I disable my button, I get the output as the image on the left, however, I want it to look like the image on the right!
<Button x:Name="button" Height="30" Width="100" Margin="825,0,0,0" Background="Transparent"
BorderThickness="0" BorderBrush="Transparent">
<Button.Content>
<Border CornerRadius="12.5" Height="25" Width="95" Margin="0" BorderBrush="Gray"
BorderThickness="4,4,4,4" Background="Gray">
<TextBlock Text="Back" HorizontalAlignment="Center" VerticalAlignment="Top"
Margin="12,0,13,0" Foreground="White"/>
</Border>
</Button.Content>
</Button>
Content is only one part of Button. The rest is determined by Template.
If multiple buttons should have custom apperance, the Template should be set in buttons Style. For one button it can be done inplace:
<Button x:Name="button" Content="Back" Height="30" Width="100" Margin="825,0,0,0" Background="Transparent"
BorderThickness="0" BorderBrush="Transparent">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border CornerRadius="12.5" Height="25" Width="95" Margin="0" BorderBrush="Gray"
BorderThickness="4,4,4,4" Background="Gray">
<TextBlock Text="{TemplateBinding Content}"
HorizontalAlignment="Center" VerticalAlignment="Top"
Margin="12,0,13,0" Foreground="White"/>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
if you are going to reuse the template, declare it as Resource
<Window.Resources>
<ControlTemplate TargetType="Button" x:Key="RoundBtn">
<Border Name="roundBorder" CornerRadius="12.5" Height="25" Width="95" Margin="0" BorderBrush="Gray"
BorderThickness="4,4,4,4" Background="Gray">
<TextBlock Text="{TemplateBinding Content}"
HorizontalAlignment="Center" VerticalAlignment="Top"
Margin="12,0,13,0" Foreground="White"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="roundBorder" Property="Background" Value="Green"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
and set button Template using resource:
<Button x:Name="button" Content="Back" Height="30" Width="100"
Template="{StaticResource RoundBtn}"
Margin="825,0,0,0" Background="Transparent"
BorderThickness="0" BorderBrush="Transparent"/>
This should work for you. I've used an outer grid with a blue background so that I could be sure it was all working, but just remove that and move the style to whichever resources you need to. Explanation as comments within the xaml:
<Grid Background="Blue">
<Grid.Resources>
<!-- Override the default button style, otherwise you get a grey
rectangle behind the ellipse when disabled -->
<Style TargetType="Button" x:Key="MyButtonStyle">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter x:Name="MyContentPresenter"
Content="{TemplateBinding Content}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Button x:Name="button" Height="30" Width="100"
BorderThickness="0" BorderBrush="Transparent" IsEnabled="false"
Style="{StaticResource MyButtonStyle}">
<Button.Content>
<Border CornerRadius="12.5" Height="25" Width="95">
<Border.Style>
<Style TargetType="Border">
<!-- Button is gray by default, i.e. when enabled -->
<Setter Property="Background" Value="Gray"/>
<Style.Triggers>
<!-- If the button becomes disabled then it becomes green -->
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Green" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock Text="Back" HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="White"/>
</Border>
</Button.Content>
</Button>
</Grid>
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>
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}">
I'm trying to trigger a setter property in c# code manually, however I'm not sure whether this is possible?
C#;
// apply this setter to the control
myControl.FindResource("StandardTextBoxStyle") as Style;
// how can I trigger ErrorTemplateSetter from here!?
My style;
<Style TargetType="{x:Type TextBox}" x:Key="StandardTextBoxStyle">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Validation.ErrorTemplate" x:Name="ErrorTemplateSetter">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="true">
<Border Background="OrangeRed" DockPanel.Dock="right" Margin="5,0,0,0"
Width="20" Height="20" CornerRadius="5"
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="red" BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>