I am trying to animate the line that strikes through text in a textblock.
Here is what I have so far.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style x:Key="TextBlockEliminated">
<Setter Property="Control.FontSize" Value="18"/>
<Setter Property="Control.FontWeight" Value="Bold"/>
<Setter Property="Control.Foreground" Value="Gray"/>
<Setter Property="TextBlock.TextDecorations">
<Setter.Value>
<TextDecorationCollection>
<TextDecoration x:Name="animatedStrikeThrough" Location="Strikethrough"/>
</TextDecorationCollection>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<Grid>
<TextBlock Style="{StaticResource TextBlockEliminated}">Some Text
</TextBlock>
</Grid>
Notice I do not Appy a DoubleAnimation anywhere thats because I cant figure out how to apply it to the TextDecoration PinOffset.
Have two TextBlocks stacked on top of each other, one with normal text, and the other with the strikeout applied, but its Opacity set to zero. Then, fade the opacity in and out for your animation.
Related
I am doing small WPF app for my own using Visual Studio, C#, .NET Standard and WPF in this specific project.
I have defined style for all TextBlocks and TextBoxes in Applications.Resources like below.
<Application.Resources>
<Style TargetType="TextBox">
<Setter Property="FontSize" Value="10"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="10"/>
</Style>
</Application.Resources>
Then in main window I have a grid which contains some buttons.
<Grid>
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="FontSize" Value="50" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="50"/>
</Style>
</Grid.Resources>
<Button Grid.Column="0" Content="DASHBOARD" Command="local:CustomCommands.ShowDashboard"/>
</Grid>
I would like to set for the textblocks/textboxes in this specific buttons a wider font.
I tried for many different syntax but could not manage it. I tried also do define x:Key for this style in Grid.Resources and use it in this specific Button control. This wasn't work either.
Can anyone let me know which way should I let know my application that text in this buttons would have bigger font size?
The TextBlock created for string contents by the ContentPresenter inside the Button template doesn't apply the locally-defined resources, i.e. those in your Grid.
The easiest way to solve your problem would be to explicitly define a TextBlock as the Button's content.
<Grid>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="50"/>
</Style>
</Grid.Resources>
<Button Grid.Column="0" Command="local:CustomCommands.ShowDashboard">
<TextBlock Text="DASHBOARD" />
</Button>
</Grid>
I'm using a resource dictionary in my wpf proyect.
The dictionary has these 2 styles:
<Style x:Key="MyMenu" TargetType="Menu">
<Setter Property="Background" Value="Black"/>
<Setter Property="Foreground" Value="White"/>
</Style>
<Style x:Key="MyToolbar" TargetType="ToolBar">
<Setter Property="Background" Value="Black"/>
</Style>
And in my XAML file, I use these 2 styles as it follows:
For the menu:
<Menu Name="menuMainBar" Style="{DynamicResource MyMenu}" IsMainMenu="True" VerticalAlignment="Top" Margin="0,10,0,0">
<MenuItem ...
</Menu>
For the toolbar:
<ToolBarTray Name="toolBarTrayRigth_wargames" Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Top" Width="50">
<ToolBar Name="toolBarRigth_wargames" Style="{StaticResource MyToolbar}" BorderThickness="0,0,1,0">
<Button ...
</ToolBar>
</ToolBarTray>
This is the result:
As you can notice, the menu takes the style correctly, but the toolbar isn't affected by the style at all.
I tried removing all the style elements from the toolbartray tag, as it follows:
<ToolBarTray Name="toolBarTrayRigth_wargames">
...
</ToolBarTray>
And now the toolbar works, but as you can see, now the toolbarTray is not how I want it to be (I want a vertical toolbar, not a horizontal toolbar):
I also tried setting the background of the ToolBar directly in the xaml file:
<ToolBarTray Name="toolBarTrayRigth_wargames" Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Top" Width="50">
<ToolBar Name="toolBarRigth_wargames" BorderThickness="0,0,1,0" Background="Black">
<Button ...
</ToolBar>
</ToolBarTray>
...and it works:
But I don't want to do that, I want to use a resource dictionary for my toolbar's style.
any ideas on how to achieve that?
I found, bizarrely, that if I set the Orientation of the parent ToolBarTray to Horizontal, that your ToolBar style was able to set the background on the ToolBar.
I also found that with the ToolBarTray orientation still being Vertical, this worked to set the ToolBar's background:
<Style x:Key="MyToolbar" TargetType="ToolBar">
<Style.Triggers>
<!--
This is intentional. A conventional setter was found not to set the background
when the parent ToolBarTray's Orientation was Vertical.
-->
<DataTrigger Binding="{Binding Source={x:Null}}" Value="{x:Null}">
<Setter Property="Background" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
I find this very strange.
as #EdPlunkett found, its a strange Setter in the default template in the Trigger for Vertical Orientation:
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="Margin" TargetName="Grid" Value="1,3,1,1"/>
<Setter Property="Style" TargetName="OverflowButton">
<Setter.Value>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Background" Value="#FFEEF5FD"/>
you can edit the template (in Document Outline panel, right click on the ToolBar element > Edit Template > Edit a Copy...), and remove this Setter.
I have Style that applies to all of the buttons of my application:
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse x:Name="StatusButtonCircle" Stroke="Black" StrokeThickness="0" Fill="AliceBlue" Stretch="Uniform">
<Ellipse.Width>
<Binding ElementName="StatusButtonCircle" Path="ActualHeight"/>
</Ellipse.Width>
</Ellipse>
<Ellipse x:Name="StatusButtonCircleHighlight" Margin="4" Stroke="Black" StrokeThickness="2" Stretch="Uniform">
<Ellipse.Width>
<Binding ElementName="StatusButtonCircleHighlight" Path="ActualHeight"/>
</Ellipse.Width>
</Ellipse>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
... some Triggers here
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I change properties (e.g. FontWeight, FontSize etc.) in XAML? I tried this:
<Button FontWeight="Bold" FontSize="30" Foreground="Red">
</Button>
In the designer-view, I see the changes. But during runtime those changes are not applied.
After some investigation, I also have a Style for all TextBlock like this:
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="16" />
<Setter Property="FontFamily" Value="Segoe UI Semibold" />
<Setter Property="Foreground" Value="White" />
</Style>
This Style seems to override the TextBlock that is used on the Button. I still can't change the Text Properties in XAML.
Here's what it looks like if I use the Styles above in an empty project:
In the designer, the changes are applied, during runtime the one from the TextBlock are applied. If I assign a x:Key to the TextBlock, it works fine. But then I have to assign this Style to every TextBlock used in the app manually.
You are facing typical style inheritance issue in wpf.
A control looks for its style at the point when it is being initalized. The way the controls look for their style is by moving upwards in logical tree and asking the logical parent if there is appropriate style for them stored in parent's resources dictionary.
In your case, you are using ContentPresenter in button as a default behaviour. and it is using TextBlock to represent text in button by default.
Therefore at the time of initialization, ContentPresenter finding TextBlock style and applying to represent content in button.
If you want to restrict ContentPresenter to look for the style then you have to bind a blank style to content presenter so that it will not look for any further style.
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse x:Name="StatusButtonCircle" Stroke="Black" StrokeThickness="0" Fill="AliceBlue" Stretch="Uniform">
<Ellipse.Width>
<Binding ElementName="StatusButtonCircle" Path="ActualHeight"/>
</Ellipse.Width>
</Ellipse>
<Ellipse x:Name="StatusButtonCircleHighlight" Margin="4" Stroke="Black" StrokeThickness="2" Stretch="Uniform">
<Ellipse.Width>
<Binding ElementName="StatusButtonCircleHighlight" Path="ActualHeight"/>
</Ellipse.Width>
</Ellipse>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center">
<ContentPresenter.Resources>
<Style TargetType="TextBlock" BasedOn="{x:Null}"/>
<!-- Assigned Blank style here therefore it will not search for any further style-->
</ContentPresenter.Resources>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You can do it with the BasedOn. I show you an example.
<Window.Resources>
<Style TargetType="ToggleButton" BasedOn="{StaticResource DefToggleButton}">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Content" Value="Some Cool Stuff"/>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="More Stuff"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Here in my resources I have DefToggleButton, now in my xaml file I can set up any Property according to my need (which in this case is the FontWeight and Content Property).
I think if you remove the Template from your Style, then you can do what you want to do, like this:
<Window.Resources>
<Style TargetType="Button" x:Key="stBtn>
<Setter Property="Background" Value="Blue" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontFamily" Value="Segoe UI Semibold" />
</Style>
</Window.Resources>
The Template that you have says, that all Buttons should be shown as a Border with a ContentPresenter inside, which is not what you have asked.
Without the Template, you can define your Buttons like this:
<Button Content="Hi!" Style="{StaticResource stBtn}" Foreground="Red" >
Like this, you have a Blue Button with Red Foreground.
=================
Edit
So what if you define a Template, and use it in you style, like this?
Then, by TemplateBinding you can define that the Foreground and teh Content come later, when the Button is actually defined.
<Window.Resources>
<ControlTemplate x:Key="ctBtn" TargetType="{x:Type Button}">
<Label Background="Green" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}"/>
</ControlTemplate>
<Style x:Key="stBtn2" TargetType="{x:Type Button}">
<Setter Property="Template"
Value="{StaticResource ctBtn}" />
</Style>
<Window.Resources>
Then by defining the Button:
<Button Content="Hi!" Style="{StaticResource stBtn2}" Foreground="Red" >
===============
Edit2
So the general idea is that you can define a TemplateBinding for the properties of the elements in your template. So for example,you have an Ellipse in your template:
<Ellipse Fill="{TemplateBinding BorderBrush}" />
This defines that the Fill property of your Ellipse comes from the BorderBrush of your Button (Assuming that the template is targeting a Button)
Accordingly, you can put a Label in your Template, and set a TemplateBinding for its Forground and FontWeight property.
<Label Foreground="{TemplateBinding Foreground}" />
First, for this issue to be reproduced, Styles need to be set within a ResourceDictionary which is then added to Application.Resources (precisellyTextBlock global style). Setting Styles within for example Window.Resources will not reproduce the issue.
Global TextBlock Style is applied to the TextBlock created by ConentPresenter
As noticed in the question, the issue is that the global (keyless) Style for TextBlock is applied to the TextBlock created by ContentPresenter when it concludes the content to display is a string. For some reason this doesn't happen when that Style is defined within Window.Resources. As it turns out, there is more to this than just "controls are looking for their styles within their parent's resources".
ControlTemplate is a boundary for elements not deriving from Control class
For TextBlock (which doesn't derive from Control class, but from UIElement) within ControlTemplate, it means that wpf will not look for it's implicit Style beyond it's templated parent. So it won't look for implicit Style within it's parent's resources, it will apply application level implicit Style found within Application.Resources.
This is by design (hardcoded into FrameworkElement if you will), and the reason is exactly to prevent issues like this one. Let's say you're creating a specific Button design (as you are) and you want all buttons in your application to use that design, even buttons within other ControlTemplates. Well, they can, as Button does derive from Control. On the other hand, you don't want all controls that use TextBlock to render text, to apply the implicit TextBlock Style. You will hit the same issue with ComboBox, Label... as they all use TextBlock, not just Button.
So the conclusion is: do not define global Style for elements which don't derive from Control class within Application.Resources, unless you are 100% sure that is what you want (move it to Window.Resources for example). Or, to quote a comment I found in source code for MahApps.Metro UI library: "never ever make a default Style for TextBlock in App.xaml!!!". You could use some solution to style the TextBlock within your Button's ControlTemplate, but then you'll have to do it for Label, ComboBox, etc... So, just don't.
I have the following style for validating input in my controls:
<Style x:Key="MyErrorTemplate" TargetType="Control">
<Style.Setters>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate x:Name="ControlErrorTemplate">
<StackPanel Orientation="Vertical" Height="Auto">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Red" FontSize="20">!</TextBlock>
<AdornedElementPlaceholder x:Name="Holder"/>
</StackPanel>
<Label Foreground="Red" Content="{Binding ElementName=Holder,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
If an error happens, the error message in the label appears under the control (e.g. textbox) and overlaps the control below. I made StackPanel's Height="Auto", but it didn't help. Each control is in a Grid cell, and the Grid's row Height is also Auto.
Could you please tell me what I am missing? I want the error message to push what is below down.
Thanks.
Validation.ErrorTemplate shows error feedback on an adorner layer. This means all controls in this template will not be considered when the layout system is measuring and arranging the controls on the adorned element layer.
I found this and thanks LPL, i did not know that about the adorner layer.
My solution was a margin "hack". I just used the trigger:
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="Margin" Value="0,0,0,28"/>
</Trigger>
</Style.Triggers>
To increase the bottom margin of the adorned textbox. I set the margin large enough to make room for a single string textblock/label and then the content below was moved down
I have a simple user control with a TextBox. I want to change the color of user control when the TextBox gets the focus. This is what I have:
<UserControl x:Class="OutLookContactList.ContactSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root" MinHeight="30" Loaded="UserControl_Loaded">
<UserControl.Resources>
<Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter TargetName="root" Property="Background" Value="{StaticResource OnMouseOverColor}" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
But I get the errot "TargetName property cannot be set on a style Setter". How can I Set the back ground color of user control when text box gets the focus?
Thanks a bunch
Will it work to wrap the contents of your UserControl inside a Border object? If so, you can simply style the Border like so:
<UserControl x:Class="Sample2.ContactSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="75" Width="300">
<Border>
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocused, ElementName=txtSearch}" Value="true">
<Setter Property="Background" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel>
<TextBox x:Name="txtSearch" Text="Search" />
<TextBox Text="Other" />
</StackPanel>
</Border>
</UserControl>
Update: (Answering Sheraz' Questions)
I'm not sure why ElementName doesn't work for accessing children within a UserControl. It might have something to do with the way the visual tree is constructed.
As for Trigger vs DataTrigger: Trigger is for dependency properties and DataTrigger is for databound properties (data or other controls). Since you are trying to style the Border, it makes more sense to place the DataTrigger there and have it watch the TextBox than to have the TextBox change the appearance of the Border.
As I understand it, the TargetName property of Setter is only applicable within a DataTemplate or ControlTemplate. (Info from Dr. WPF in this forum post)
If you were changing the background of the text box you need to remove the TargetName property:
<Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Background" Value="{StaticResource OnMouseOverColor}" />
</Trigger>
</Style.Triggers>
</Style>
and change the TextBox that wants this style to be:
<TextBox Style="{StaticResource searchTextBoxStyle}" .... />
However, as you want to change the value of the parent user control this won't give you want you want.
You could certainly do it in the code behind by adding a GotFocus event handler and putting the code to change the background colour in there.
Here's some XAML that works in Kaxaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Style>
<Style TargetType="Page">
<Setter Property="Background" Value="#CCCCD0" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=txtSearch, Path=IsFocused}"
Value="true">
<Setter Property="Background" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</Page.Style>
<TextBox x:Name="txtSearch" Width="100"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Page>
You would change the Page object with your UserControl. I find it much easier to test these sorts of things out in a rapid prototyping tool such as Kaxaml before coding up the UserControl in VS.
Note that you have to set the default colour (in this case #CCCCD0) via a property setter and not via an attribute on the Page itself. This is because the attribute would override the value set by the trigger (because it's a style trigger), so even though the trigger would fire, it would always be trumpted by the local attribute specification, meaning that it wouldn't change. I only point this out because it's a fairly common gotcha.