Why can I not change textbox background after applying style? - wpf

<Style x:Key="Border"
TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border BorderThickness="1">
<ScrollViewer Margin="0"
x:Name="PART_ContentHost" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Why I cannot change TextBox background after applying style?
<TextBox Style="{StaticResource Border}"
Background="Bisque"
Height="77"
Canvas.Left="184"
Canvas.Top="476"
Width="119">Text box</TextBox>

<Style x:Key="Border" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border Background="{TemplateBinding Background}" BorderThickness="1">
<ScrollViewer Margin="0" x:Name="PART_ContentHost" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You need to add the following line:
Background="{TemplateBinding Background}"
You overwrite the original Control Template of textbox. Background is a child of Template. You need to bind it to the target textbox again.

By overwriting the template of the control, you are literally defining how it will be shown to the user. In your template, you don't take into account any 'settings' in the control, so it will be always drawn as Border with a ScrollViewer inside.
If you want to use the properties of the control to customize some parts of your template, you can bind properties of your template contents to properties in your control using TemplateBinding
Ex:
<Style x:Key="Border"
TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border BorderThickness="1"
Background="{TemplateBinding Background}">
<ScrollViewer Margin="0"
x:Name="PART_ContentHost" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In this case, you are binding the Background property of your Border (Background=) to the Background property of your TextBox ({TemplateBinding Background)
So, in summary, you use this notation in your bindings:
ThePropertyIWantToSet="{TemplateBinding PropertyInMyControl}"

Related

Xaml switch between TextBlock and TextBox

I've noticed that TextBoxes are very slow and create performance issues when the Text is changed dynamically by code (I need to change the Text continuosly to 10-15 TextBoxes at the same time), so, as a workaround, I've created a custom control with a TextBlock and a TextBox:
The TextBlock is used in almost all time.
The TextBox is used only when I need to edit the Text inside the control with keyboard.
My solution is to change the template and use the TextBox when the control is focused:
(Value is a string Dependency Property)
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Value" Value="Val"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Value}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBox HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding Path=Value, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
But when I click on the control nothing happens.
I think that the problem is that the "focus state" is passed to the internal TextBox, and the control loses the "focus state".
There is a better way to create a custom "TextBox" control like this, or a way to resolve this problem?
You don't need a custom control for this, that's just adding unnecessary overhead. What you're trying to create is still a TextBox, with all the usual behavior of a TextBox (focus etc). All you need to do is change the template to a TextBlock when it's not in focus:
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<TextBlock Text="{TemplateBinding Text}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Text="Hello World" />
<TextBox Text="Goodbye World" />
</StackPanel>

Setting a property of a style's ControlTemplate in XAML

I want to access a property nested inside a style's control template. I know that you can do this in the code-behind:
GradientStop stop = (GradientStop)progressBar1.Template.FindName("gradStop", progressBar1);
stop.Color = Colors.Black;
Is it possible to do the same, but in the XAML? For example:
<ProgressBar Style="{StaticResource CustomProgressBar}" [???].Color="FF000000"/>
Can you not use TemplateBinding?
<Style x:Key="MyStyle" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Background="{TemplateBinding Background}" >
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then specify the template bound values when you apply the style.

FocusVisualStyle Template, bind property to a parent's

I have created a FocusVisualStyle for my user control and have successfully implemented the override. My problem is I would like that to use some properties from the parent, but TemplateBinding doesn't seem to work.
A simplified version of the the Control is defined as below:
<Style TargetType="{x:Type local:Thought}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ThoughtFocusStyle}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Thought}" >
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{StaticResource ThoughtBorderNormalBrush}">
<!-- other controls -->
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My custom FocusVisualStyle is defined as follows:
<Style x:Key="ThoughtFocusStyle" TargetType="{x:Type Control}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Control}">
<Border BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{StaticResource ThoughtBorderFocusBrush}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If I hard code BorderThickness in ThoughtFocusStyle it works as expected (Tab into the control), but using TemplateBinding does not. I've played around with RelativeSource but can't seem to get the syntax right (still very new to WPF).
try :
<Border BorderThickness="{Binding
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Control},
Path=BorderThickness}">

xaml border style

I create style for buttons:
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#8A88E1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
It all OK. Now I want to write part of the style that would be looked around the ellipse boundary.
Erno beat me to the answer, but here's an example:
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#8A88E1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}" Stroke="..." StrokeThickness="..." />
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You should be able to bind the Stroke to the parent BorderBrush but I haven't tested it: Stroke="{TemplateBinding BorderBrush}". However, you won't be able to directly bind StrokeThickness to the parent BorderThickness as they're two different types (Ellipse.StrokeThickness is uniform and a simple double value whereas Button.BorderThickness is of type Thickness.).
There are two options:
Set the Stroke and StrokeThickness of the ellipse or
Add a template to the border and use an ellipse in the template.
Let me know if you need help with these.

WPF Template Inheritance

I created a button. My basic requirements are rounded thicker border, with more than one color (i.e. for Buy/Sell buttons)
I was hoping that i could create the template once, and than just override the border brush like this:
<Style x:Key="BorderButton">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="2"
BorderBrush="Red"
CornerRadius="3"
Background="{x:Null}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="GreenBorderButton" BasedOn="{StaticResource BorderButton}" TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="Green" />
</Style>
but they both produce the same style.
Do i need to write out the whole template every time? seems like unnecessary code repetition (especially if 3-4 colors are desired). Hoping there is some way to inherit a template.
Your code is very close to working; the issue is that GreenBorderButton is applying the BorderBrush to the button itself, not the Border in the overridden Template.
To fix this, simply change the Border's BorderBrush to use the parent Button's BorderBrush. You can do this using a TemplateBinding like so:
<Style x:Key="BorderButton">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border"
BorderThickness="2"
BorderBrush="{TemplateBinding Property=BorderBrush}"
CornerRadius="3"
Background="{x:Null}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then, you can either use the same overridden styles like you have, or you could simply do:
<Button Style="{StaticResource BorderButton}" BorderBrush="Blue" Content="Blue" />

Resources