WPF CustomControl style not inherited by Child Control - c#

I'm trying to learn how to make a custom control. I've been searching all afternoon, but can't get my properties to be used by the child controls.
For example my TextBox subclass is TextBoxCalculator. In the control template I have a textbox and a popup.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Controls">
<Style TargetType="local:TextBoxCalculator" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TextBoxCalculator">
<Grid Name="ucGrid">
<TextBox Name="AmountTb" Text="{Binding Text }">
<!--<TextBox.Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
... How can I make this textbox style follow the one specified in the window XAML?
</Style>
</TextBox.Style>-->
</TextBox>
<Popup Name="calPopup" Placement="Top" StaysOpen="False">
... some content
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
In my window I use the control like this:
<Style TargetType="{x:Type controls1:TextBoxCalculator}" x:Key="RightCellEditCalc">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="TextAlignment" Value="Right"/>
<Setter Property="Background" Value="Red"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
<controls1:TextBoxCalculator Text="{Binding Amount, UpdateSourceTrigger=LostFocus}"
DecimalPlaces="2"
AutoPlaceDecimalPoint="True"
Style="{StaticResource RightCellEditCalc}"
Background="Green">
</controls1:TextBoxCalculator>
I would expect the background to be green, but it is white instead.
An the other hand the TextAlignment = Right seems to be working. What am I missing?

It makes no sense to define a TextBox element in the ControlTemplate of another custom TextBox control.
If you want to create a custom template for your control and base it on the default template of the TextBox control, you could right-click on a TextBox element in design mode in Visual Studio or in Blend and choose Edit Template->Edit a Copy to copy the default template into your XAML markup and then edit it as per your requirements.
This is how it looks like on Windows 8 and later:
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="#FF7EB4EA"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="#FF569DE5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
It uses TemplateBindings to bind properties of the Border element in the template to the corresponding property of the TextBox control itself.

You are not binding the background.binding it at the place you want inside your ControlTemplate.For example
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Controls">
<Style TargetType="local:TextBoxCalculator" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TextBoxCalculator">
<Grid Name="ucGrid">
<TextBox Name="AmountTb" Text="{Binding Text }" Background="{TemplateBinding Background}">
<!--<TextBox.Style>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
... How can I make this textbox style follow the one specified in the window XAML?
</Style>
</TextBox.Style>-->
</TextBox>
<Popup Name="calPopup" Placement="Top" StaysOpen="False">
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
you can use the background now.

Related

Can't change background button property anymore if mouseOver have been overridden

In the image below, I have 3 buttons (UserControls) on which I changed the default mouseOver effect. In the picture, I'm currently hovering the button 1.
Here is the code I used:
<Style x:Key="ButtonMouseOver" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border>
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#404040"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid Background="Transparent">
<ContentPresenter></ContentPresenter>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My user control buttons:
<Button HorizontalContentAlignment="Stretch" Style="{StaticResource ButtonMouseOver}" VerticalContentAlignment="Stretch" Background="{Binding ButtonColor}" BorderThickness="0">
But now, I can't change the color of my buttons anymore with the Background property. Any ideas why?
When you override a ControlTemplate you have to be careful to use TemplateBinding to bind to properties of the templated target control, otherwise they take their default value or the explicit value that you have assigned in the template, but they cannot be overriden directly or in a Style.
In your example, you have to bind the Background of the Border with a TemplateBinding so that it uses the value from the Background property of the templated Button. You should do that for all properties of Button to enable different styles.
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<!-- ...other definitions -->
</ControlTemplate>
From the documentation of TemplateBinding:
Links the value of a property in a control template to be the value of another property on the templated control.
Here is a simplified version of your control template with a template binding for background, as well as a default value defined in its style, that can be overriden in another style or directly on the button.
<Style x:Key="ButtonMouseOver" TargetType="{x:Type Button}">
<Setter Property="Background"
Value="#777777"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="MyBorder"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="MyBorder"
Property="Background"
Value="#404040"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

WPF - Font Awesome icons not showing in runtime

I'm building WPF application and I want to use icons from Font Awesome. I have Font Awesome included in styles, and a font family specified in fields where I want to use it. The problem is icons are showing properly in the design window but change to crossed squares during runtime.
There is my Fonts XAML
<FontFamily x:Key="ArconRegular">pack://application;,,,/Fonts/#Arcon</FontFamily>
<FontFamily x:Key="ArconRounded">pack://application;,,,/Fonts/#Arcon Rounded-</FontFamily>
<FontFamily x:Key="FASolid">pack://application;,,,/Fonts/#Font Awesome 5 Free Solid</FontFamily>
<Style TargetType="{x:Type Control}" x:Key="BaseStyle">
<Setter Property="FontFamily" Value="{StaticResource ArconRegular}"/>
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="BaseTextBlockStyle">
<Setter Property="FontFamily" Value="{StaticResource ArconRegular}"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseStyle}"/>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseStyle}"/>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseStyle}"/>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseTextBlockStyle}"/>
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource BaseStyle}"/>
<system:String x:Key="FAMinimizeIcon"></system:String>
<system:String x:Key="FAMaximizeIcon"></system:String>
<system:String x:Key="FACloseIcon"></system:String>
The Buttons XAML (I want to use icons on buttons)
<Style TargetType="{x:Type Button}" x:Key="WindowControlButton" BasedOn="{StaticResource BaseStyle}">
<Setter Property="FontFamily" Value="{StaticResource FASolid}"/>
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="Foreground" Value="{StaticResource ForegroundMainBrush}"/>
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleX="1.5"/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource BackgroundLightBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
And finally MainWindow XAML (a part of it where i want to use them)
<!-- Window Buttons -->
<StackPanel Grid.Column="2" Orientation="Horizontal">
<Button Style="{StaticResource WindowControlButton}" Content="{StaticResource FAMinimizeIcon}" Command="{Binding MinimizeCommand}"/>
<Button Style="{StaticResource WindowControlButton}" Content="" Command="{Binding MaximizeCommand}"/>
<Button Style="{StaticResource WindowCloseButton}" Content="" Command="{Binding CloseCommand}"/>
</StackPanel>
As you can see, I tried specifying icon code in separate string and using StaticResource but nothing works.
In my case it was missing FontFamily="{TemplateBinding FontFamily}" in the ControlTemplate
Had a same issue, i.e Showing ok in Design mode but no Runtime. For me it was because fontawesome was not included in the assembly.
Changed (in visual studio) the .otf file's Build Action to "Resource". You may want to check if the file is included in your assembly by decompiler.

How to create a new button style?

Hello so I use a lot of button and I don't like the "animation" when my mouse is over the button so I found this :
<Button.Style>
<Style
TargetType="{x:Type Button}">
<Setter
Property="OverridesDefaultStyle" Value="True"/>
<Setter
Property="Margin" Value="5"/>
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type Button}">
<Border
x:Name="border"
BorderBrush="{x:Null}"
BorderThickness="3"
Background="{TemplateBinding Background}"
CornerRadius="0"
Padding="0">
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger
Property="IsMouseOver"
Value="True">
<Setter
Property="BorderBrush"
TargetName="border"
Value="#252525"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
It works great, so I was wondering how to create a new Style named "NoMouseOver" that I can just choose here : http://image.noelshack.com/fichiers/2016/42/1477013610-style.png
Although you could have find the answer to your question on a quick search (here on stackoverflow or google), here is a simple answer to your question:
Create the style in the Resources-section of your Window/UserControl:
<Windows.Resources>
<Style x:Key="NoMouseOverStyle" TargetType="Button">
...
</Style>
</Window.Resources>
Afterwards you can select this style in the properties, or directly use it in your XAML.
<Button Style={StaticResource NoMouseOverStyle} />
Keep in mind that if you want to use this style in different windows or user controls, you may want to use ResourceDictionarys.
EDIT
As Steffen said, i removed the DynamicResource and replaced it with StaticResource.
previous answer is correct, but i would use StaticResource instead DynamicResource for performance reasons.
Regards
Steffen

Custom Style Button With Modified Background

I have a Button that I want to have an Orange Background with a White Foreground. When I mouse over the Button I would like it to display in DarkOrange. This is the Style I am using at the moment.
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="DarkOrange"/>
</Trigger>
</Style.Triggers>
</Style>
If I don't modify the original Background color of the my Button this style works fine. For example;
<Button Grid.Row="2" Content="SIGN IN" />
has no issues. However, when I want to change the default Background of the Button, i.e
<Button Grid.Row="2" Content="SIGN IN" Background="Orange"/>
the style does not work. I assume this is because I am now overriding the Background property that the IsMouseOver is attempting to change.
Is there a way I can achieve both a modified default Background and a IsMouseOver effect? I have also tried setting <Border Background="Orange"> but to no effect still.
You could just add a setter to your Style instead of adding a Background property to your Button. Like this:
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Orange"/>
<Setter Property="Template">
...
</Setter>
<Style.Triggers>
...
</Style.Triggers>
</Style>
Here is an another example of how to use it.
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate x:Name="Border" TargetType="{x:Type Button}">
<Border x:Name="Border" Background="{TemplateBinding Background}">
<ContentPresenter x:Name="CP" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="CP" Property="TextBlock.Foreground" Value="White"/>
<Setter TargetName="Border" Property="Background" Value="DarkOrange"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This working fine with
<Button Grid.Row="2" Content="SIGN IN" Background="Orange"/>

How to set a borderless button which changes its color when mouse hovering in WPF

I want to override all my button's style to a borderless grayish button which highlights when hover on.
I wrote like below:
If I remove the template section (I even have no idea of what does it do), the button will have a border even if I have set BorderThickness to 0.
But if I keep the template section, the button will not change its background color at all.
So what can I do to keep both features and why my xaml won't work?
BTW, where can I find a full list of properties/triggers that I can set for certain type of control like button?
<Style TargetType="{x:Type Button}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="Background" Value="{StaticResource TitleBrush}" />
<Setter Property="Foreground" Value="{StaticResource WhiteTextBrush}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter Content="{TemplateBinding Content}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource HoverBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
Why BorderThickness value not reflected to control?
https://stackoverflow.com/a/16649319/440030
Why your xaml won't work?
Because, you set Template property of button with a simple content presenter, So Button ignore all control property and reflect your template. One way is improve your Template property with a by example label:
<ControlTemplate TargetType="{x:Type Button}">
<Label Content="{TemplateBinding Content}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="Black"/>
</ControlTemplate>
Try something like this it will work
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="Rect" Width="100" Height="100" Fill="Aqua"/>
<Viewbox>
<ContentControl Margin="20" Content="{TemplateBinding Content}"/>
</Viewbox>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Rect" Property="Fill" Value="Orange"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Grid.Resources>
<Button Template="{StaticResource buttonTemplate}">OK</Button>
</Grid>

Categories

Resources