I have simple ToggleButton and when IsChecked i want to change only the text.
I want all other properties like border and background will be Transparent but it seems that i still have this background style:
<ToggleButton x:Name="changeButBorderedBlinky" Content="EDIT" Width="40" Height="40" Background="Transparent">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Content" Value="Done"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
One thing that is often annoying is some visual aspects of the default WPF controls are coded in a way so as they are not configurable. The MouseOver Background is an example (scrollbar sizes is another... grrr!!!). You can solve this though by defining your own Template for the ToggleButton and eliminate that MouseOver trigger. Here is a simple example:
<ToggleButton x:Name="changeButBorderedBlinky" Width="40" Height="40" Background="Transparent">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Content" Value="EDIT"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<ContentPresenter x:Name="contentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
Focusable="False"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Content" Value="Done"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Also, in order to change a property in a trigger it has to be set in a style, not directly. That is why your Content doesn't change in your MouseOver Trigger. If you remove the property setting for it and
add it into the Style with a Setter, it will allow the trigger to change it.
One downside to all this is it overrides all the default template triggers so you won't see when the ToggleButton is checked anymore unless you add a trigger for "IsChecked" too. (and if you need to alter the Background in the trigger, move the Background Property to a Setter like I did for Content)
Hope that helps...
Sorry to revive an old thread, but (for someone struggling) the following worked for me. This can be in App.xaml file under Application.Resources tag or directly in the Window.Resources. I originally needed it for a UWP application, then had to adapt for WPF for a different project:
<Style TargetType="ToggleButton" x:Key="TransparentToggleButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid x:Name="RootGrid" Background="Transparent">
<ContentPresenter x:Name="ContentPresenter" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then just style your ToggleButton:
<ToggleButton Style="{StaticResource TransparentToggleButtonStyle}">
(whatever content you want to present)
</ToggleButton>
Hope this helps someone,
Related
I have the below code set for a custom button. But I want to change the background for a single button.
<Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="rectangle" Fill="#FF2F2FEA" Stroke="Black">
<Rectangle.Effect>
<DropShadowEffect ShadowDepth="3"/>
</Rectangle.Effect>
</Rectangle>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Bottom" Margin="2.833,0,2.5,1.162" RenderTransformOrigin="0.5,0.5" Width="69.667"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
The code below is meant to override the background color but doesn't. What am I missing? Thanks
<Style x:Key="SpecialButton" TargetType="Button" BasedOn="{StaticResource myButtonStyle}">
<Setter Property="Background" Value="PaleGreen" />
<Setter Property="Height" Value="19.96" />
</Style>
Add <Setter Property="Background" Value="#FF2F2FEA" /> to the myButtonStyle. And change the Fill on the Rectangle to Fill="{TemplateBinding Background}"
<Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#FF2F2FEA" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="rectangle" Fill="{TemplateBinding Background}" Stroke="Black">
<Rectangle.Effect>
<DropShadowEffect ShadowDepth="3"/>
</Rectangle.Effect>
</Rectangle>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Bottom"
Margin="2.833,0,2.5,1.162"
RenderTransformOrigin="0.5,0.5" Width="69.667"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
After this, the two Buttons should show up properly.
<StackPanel>
<Button Content="BASE" Style="{StaticResource myButtonStyle}"></Button>
<Button Content="DERIVED" Style="{StaticResource SpecialButton}"></Button>
</StackPanel>
Result:
Explanation: if you change the Template of a Control you have to "wire-up" its properties (like Background, Foreground, HorizontalContentAlignment etc) to properties of elements in the ControlTemplate. After all you want to give the ability to end users of the control to modify the color, alignment etc, and not just have a Control with a static visual tree.
In the illustration below you can see a custom control that I'm currently creating with a view to learning as much as I can about the whole process of control creation.
Currently I'm trying to both simplify the xaml by effectively refactoring repetitive style elements out into a separate style and achieve a disabled look for images when the buttons in which they are situated are disabled.
In the xaml below you can see both the button style I've created and the data trigger for the image. In theory both are being applied to the second button on the left, but quite clearly they aren't being.
I think that the basic style definitions are correct but it may be that they are in the incorrect place. Can anyone advise as to what it is that I'm currently doing wrong.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ViewToLearn.WpfControls">
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type UIElement}, AncestorLevel=1}, Path=IsEnabled}"
Value="False">
<Setter Property="Opacity"
Value="0.2"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush"
Value="Transparent" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="Margin"
Value="4" />
</Style>
<Style TargetType="{x:Type local:VtlDataNavigator}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:VtlDataNavigator}">
<StackPanel Orientation="Horizontal">
<Button BorderBrush="Transparent"
Background="Transparent"
BorderThickness="0">
<StackPanel Margin="4">
<Image Source="/ViewToLearn.WpfControls;component/Resources/Images/button_rounded_blue_first24.png" />
</StackPanel>
</Button> <!-- This is the button that should be influenced by the style and trigger defined above, but clearly it isn't -->
<Button IsEnabled="False">
<StackPanel Margin="4">
<Image Source="/ViewToLearn.WpfControls;component/Resources/Images/button_rounded_blue_previous24.png" />
</StackPanel>
</Button>
<TextBox Text="{Binding Path=RecordIndex,RelativeSource={RelativeSource TemplatedParent}}"
VerticalAlignment="Center"
IsReadOnly="True"
BorderThickness="0"
Margin="4" />
<TextBlock Text="of"
VerticalAlignment="Center"
Margin="4" />
<TextBlock Text="{Binding Path=RecordCount,RelativeSource={RelativeSource TemplatedParent}}"
VerticalAlignment="Center"
Margin="4" />
<Button BorderBrush="Transparent"
Background="Transparent"
BorderThickness="0">
<StackPanel Margin="4">
<Image Source="/ViewToLearn.WpfControls;component/Resources/Images/button_rounded_blue_next24.png" />
</StackPanel>
</Button>
Your second button has IsEnabled="false"
That makes the difference.
But if you want the background to be the same for all buttons, enabled or not, you have to got in the triggers.
The best way to generate the default style and template with triggers is to put a dummy/test button in a window, right click on it, Edit Template/Edit a copy.
VS will generate much code. You 'll see inside the "full" template" of the button + the triggers.
Inside there is a trigger for different appearance when disabled :
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<!-- ... -->
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" TargetName="border" Value="#FFF4F4F4"/>
<Setter Property="BorderBrush" TargetName="border" Value="#FFADB2B5"/>
<Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="#FF838383"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
It's that template you can take inspiration from to update your style (without trigger when disabled):
<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush"
Value="Transparent" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="Margin"
Value="4" />
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<!-- no trigger int he template -->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Notes regarding your code because it seems you are eager to learn :
Don't have to set Background, BorderThickness, BorderBrush for every button, it is already done in your Button style
The StackPanel around every Image is the same and can be put inside the template around the ContentPresenter tag
If VtlDataNavigator is a Usercontrol, you can put all the content of <ControlTemplate TargetType="{x:Type local:VtlDataNavigator}"> inside the <UserControl> tag.
It makes the control more reusable (don't have to provide the template in every Window for the control)
Regards
I have a simple xaml example and I want to change CornerRadius property, which is set through ControlTemplate of Button. I need a way to change it through Button. One use case is: I have 2 buttons, one sets to "BigRadius" and another one sets to "SmallRadius". If I change the default one on Border, then both buttons will have the same CornerRadius. Is there a way to do this in XAML only?
<Window x:Class="StyleDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border CornerRadius="5" BorderBrush="Blue"
BorderThickness="5"
Width="80"
Height="40"
x:Name="BaseBorder">
<ContentPresenter Content="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Grid" x:Name="GridWithMarginStyle">
<Setter Property="Margin" Value="12"></Setter>
</Style>
</Window.Resources>
<StackPanel>
<!--This button will have a big corner radius-->
<Button Name="Ok" Content="Ok"></Button>
<!--This button will have a small corner radius-->
<Button Name="CancelBtn" Click="CancelBtn_Click">Cancel</Button>
</StackPanel>
</Window>
You will need two styles for the Button to achieve what you are doing or create a Custom Button to implement CornerRadius as DependencyProperty, and bind it with CornerRadius of Border in ControlTemplate.
<Style TargetType="Button" x:Key="LargeRadiusStyle">
<Setter Property="Background" Value="White" />
<Setter Property="TextBlock.TextAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="10" Background="White" BorderBrush="Black" BorderThickness="1" >
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Button" x:Key="SmallRadiusStyle">
<Setter Property="Background" Value="White" />
<Setter Property="TextBlock.TextAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="3" Background="White" BorderBrush="Black" BorderThickness="1" >
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Not sure what you have against DPs. You need SOMETHING to tell the button whether you want the big radius or the small radius. WPF can't read your mind (yet) :). If you don't want a custom button class, then you can use an attached property.
I'm interested in styling the column headers on an Xceed DataGrid. The goal is to make the background color grey, with a dark grey border around each header column cell. It seemed to me like the best way to do this was to style the ColumnManager:
<Style TargetType="{x:Type xcdg:ColumnManagerCell}">
<Setter Property="Template" Value="{StaticResource ColumnManagerCellTemplate}"/>
<Setter Property="BorderBrush" Value="#c5c5c5"/>
<Setter Property="BorderThickness" Value="1,1,1,1"/>
</Style>
Using this template:
<ControlTemplate x:Key="ColumnManagerCellTemplate" TargetType="xcdg:ColumnManagerCell">
<Grid Background="LightGray" >
<xcdg:DataCell Content="{TemplateBinding Content}"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Background="LightGray"
HorizontalContentAlignment="Left"
VerticalContentAlignment="Center"
BorderBrush="DarkGray"
BorderThickness="2"/>
</Grid>
</ControlTemplate>
The background color shows up correctly, as does the content, but I cannot get a dark grey border to show up around each cell. (Or any color border at all.) What am I missing? Shouldn't the BorderBrush and BorderThickness properties control this? They seem to work on the rest of the cells in the grid, but not the ColumnManagerCells.
You should use a border instead of the grid and then hook up the template bindings for the border like this:
<Style TargetType="{x:Type xcdg:ColumnManagerCell}">
<Setter Property="Background" Value="LightGray" />
<Setter Property="BorderBrush" Value="#c5c5c5"/>
<Setter Property="BorderThickness" Value="1,1,1,1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"
ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I should mention that my default ControlTemplate for ColumnManagerCell is a ContentPresenter instead of DataCell like below:
<xcdg:DataCell Content="{TemplateBinding Content}" />
Are you sure your using the correct control template?
I have a ListBoxItem Style that I am trying to modify so that it will show character ellipsis when the list box is made to small. To do that I've had to get rid of the ContentPresenter in our code and replace it with a TextBlock. The ListBoxes that this is applied to are all bound via the ItemSource property.
Here is my code.
<Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="White"/>
<Setter Property="Margin" Value="0,0,0,0"/>
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<Border x:Name="Bd" SnapsToDevicePixels="true">
<!-- Before this used to be ContentPresenter but I switched it to TextBlock to get it the TextTrimming property. I can't find the right way to bind the data though.-->
<TextBlock Text="{TemplateBinding DisplayMemberPath}" TextTrimming="CharacterEllipsis" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<Rectangle x:Name="HoverRectangle"
Stroke="{StaticResource Gold}"
StrokeDashCap="Square"
StrokeThickness="0"
SnapsToDevicePixels="True" />
<Rectangle x:Name="KeyboardFocusRectangle"
Height="Auto"
SnapsToDevicePixels="True"
Stroke="{StaticResource BrightBlue}"
StrokeDashCap="Square"
StrokeThickness="0" />
</Grid>
<ControlTemplate.Triggers>
<!-- Bunch of Triggers in here -->
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My current TextBlock Text binding (Text="{TemplateBinding DisplayMemberPath}") is not working. What should the binding be in order to work correctly?
Your only reasonable choice here is to assume the data context of the ListBoxItem is a string, or can be displayed as such:
<TextBlock Text="{Binding}" .../>