WPF template for yes/no ToggleButton - wpf

Can anyone help me with a simple template to make a WPF ToggleButton show "yes" or "no" depending on it's toggle state?
I dont want it to look like a button though, just a piece of text that either shows as yes or no.
I'd like it as a template that I can just add as a style to all my existing Toggle controls.
I tried with Blend but I am new to templating and didn't know how to do it.

Building up on #Batuu's reply, to be just left with the content as text just update the style to
Updated
<Style x:Key="OnOffToggleStyle" TargetType="ToggleButton">
<Setter Property="Content" Value="Off"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="On">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Addition here compared to original reply is
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
You basically set the template of the button to just be the content that it holds.

You can do this easily with a style:
<Window x:Class="WpfTest.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 x:Key="OnOffToggleStyle" TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content">
<Setter.Value>
<TextBlock Text="Yes"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Content">
<Setter.Value>
<TextBlock Text="No"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<ToggleButton Style="{StaticResource OnOffToggleStyle}"/>
</Grid>
</Window>

Related

WPF foreground inheritance

I created a simple style in WPF and I cannot figure out what case A works, but not case B.
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter
TextBlock.Foreground="Red"
TextElement.Foreground="Yellow"
Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Case A:
<Button Content="Test A"/> // background is Yellow
Case B:
<Button>
<TextBlock Text="Test B"/> // background is black
</Button>
I would like to create a style for a button that change text color of its content via the ContentPresenter.
Could someone explains what is missing to make case B to work?
(Ideally it should work with any content that have a Foreground property, not only TextBlocks).
Thanks in advance,
Thank you Clemens, but in fact I would like to change foreground of one part of the template only, not the foreground of the control itself. Button is just a simple example here.
I am using the ContentPresenter in triggers too:
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="#CCFFFFFF"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="#66FFFFFF"/>
</Trigger>
</ControlTemplate.Triggers>
Set the Button's Foreground property via another Setter:
<Style TargetType="Button">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Alternatively, add a TextBlock Style to the ControlTemplate's Resources:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ControlTemplate.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
</Style>
</ControlTemplate.Resources>
<Grid>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

ToggleButton Style; Override IsEnabled

Once the ToggleButton is checked, the Button should be set to disabled and the foreground color should change. The following is not working:
<Window x:Class="WpfApplication1.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">
<Grid>
<ToggleButton Content="Hallo" Margin="113,97,72,46" >
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="IsEnabled" Value="True"/>
<Setter Property="IsChecked" Value="False"/>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Green"/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
</Grid>
How can I do this?
The appearance of disabled controls is different across different versions of windows and different Windows account settings etc, this is why it's working for others but not you. Generally speaking you should respect such settings, but if you really are adamant then you'll need to explicitly override the template as demonstrated in this question:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>

WPF AlternationIndex to control visibility of a ControlTemplate item

I am using a ControlTemplate for my ListBoxItems for a given ListBox. The ControlTemplate is defined in a Style and contains a Rectangle whose Visibility needs to be toggled based on the AlternationIndex. Although I see how to use AlternationIndex to control the background of the ListBoxItem directly, I'm not sure how I use the trigger to reference a named item in my control template. Any input is appreciated:
XAML Excerpt:
<Style x:Key="ListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid Height="84" Width="700">
<!--
TURN ME ON FOR EVERY EVEN NUMBERED LIST ITEM
-->
<Rectangle x:Name="_listItemBg" Width="700" Height="83" Opacity="0.12">
...
I have tried the following, but to no avail. The correct XAML syntax evades me:
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Rectangle.Visibility" TargetName="_listItemBg" Value="Hidden" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Rectangle.Visibility" TargetName="_listItemBg" Value="Visible" />
</Trigger>
...
Perhaps you forgot to set AlternationCount? In any case, here is a small self-contained working sample based on your code:
<Grid>
<Grid.Resources>
<PointCollection x:Key="sampleData">
<Point>1,2</Point>
<Point>3,4</Point>
<Point>5,6</Point>
</PointCollection>
</Grid.Resources>
<ListBox ItemsSource="{StaticResource sampleData}" AlternationCount="2">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid Height="84" Width="700">
<Rectangle x:Name="_listItemBg" Width="700" Height="83" Fill="Red" Opacity="0.12"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Rectangle.Visibility" TargetName="_listItemBg" Value="Hidden" />
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Rectangle.Visibility" TargetName="_listItemBg" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>

Styling TabItem when populated with ItemsSource

I'm using a WPF Tabcontrol populated with a collection using Itemssource.
<TabControl x:Name="_tabControl" ItemsSource="{Binding TabViewModelList}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding TabCaption}"/>
<Setter Property="Content" Value="{Binding TabContent}"/>
<Setter Property="IsSelected" Value="{Binding IsDefault}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Now I want to set my TabItem-style in my App.xaml(or other resourcefile) like this:
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Background="LightBlue"
BorderBrush="Black"
BorderThickness="1,1,1,1"
CornerRadius="6,6,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="LightGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
..but the ItemContainerStyle, of course overrides the controltemplate.
How do I combine these two so I can load my tabcontrol dynamically and still be able to style my TabItems the way I want to?
Ok... Solved my own problem. Pretty obvious..
Named my template
<Style TargetType="{x:Type TabItem}" x:Key="TabItemTemplate">
Added a BasedOn property like this:
<Style TargetType="TabItem" BasedOn="{StaticResource TabItemTemplate}">
But if I could combine them into one template please let me know...

WPF Binding & Converters

I've been recently playing with WPF and I've come across a number of problems that I can't solve. I have the following code in my generic.xaml:
<Style TargetType="{x:Type local:ClearButton}">
<Style.Resources>
<con:ValueConverter x:Key="converter" />
</Style.Resources>
<Setter Property="Width" Value="20" />
<Setter Property="Height" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ClearButton}">
<Grid>
<Image Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="/WPF-Libraries;component/Resources/ClearEnabled.png" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BitmapEffect">
<Setter.Value>
<OuterGlowBitmapEffect Opacity="0.5" GlowColor="Red" GlowSize="3" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Source"
Value="/WPF-Libraries;component/Resources/ClearDisabled.png" />
</Trigger>
<!--Binding #1-->
<Trigger Property="{TemplateBinding local:ClearButton.IsPressed}" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<!--Binding #2-->
<ScaleTransform CenterX="CONVERTER BINDING:PASS WIDTH TO CONVERTER" CenterY="CONVERTER BINDING:PASS HEIGHT TO CONVERTER" ScaleX="0.75" ScaleY="0.75" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I can't get Binding #1 to work. I want to bind the trigger to the IsPressed property of the button, what should the binding be? Also what should the binding be for Binding #2 if I want to pass the button's Width and Height to the converter?
Also I could set the trigger this way instead:
<Style TargetType="{x:Type local:ClearButton}">
<Style.Resources>
<con:ValueConverter x:Key="converter" />
</Style.Resources>
<Setter Property="Width" Value="20" />
<Setter Property="Height" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ClearButton}">
<!--Abbreviated-->
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<!--Binding #1-->
<Trigger Property="{TemplateBinding local:ClearButton.IsPressed}" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<!--Binding #2-->
<ScaleTransform CenterX="CONVERTER BINDING" CenterY="CONVERTER BINDING" ScaleX="0.75" ScaleY="0.75" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Which one is better and what would the binding be for Binding #1 and #2?
Both approaches are a little bit off. Your first approach is struggling to reach the IsPressed property using binding, however the Property property of the Trigger object is not a DependencyProperty so it doesn't support binding.
Your second approach is closer to the mark but still wrong, again uses binding on the Property property of the Trigger.
Check this out instead:
<Style TargetType="Button" x:Key="ClearButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<TextBlock
Name="x"
Text="I will change my color when ou press me"
TextAlignment="Center"
VerticalAlignment="Center"
Foreground="Red"
TextWrapping="Wrap"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter
TargetName="x"
Property="Foreground"
Value="Green"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Notice that I put the trigger logic on the control template level (specifying the target element), not on the individual element (the TextBlock in this case).

Resources