WPF MVVM change static resource style dynamically - c#

I am new to WPF and here is what I am trying to do. I want to change a button's style, which is a static resource, based on whether a radio button is checked on not. Below is sample code:
<RadioButton Name="rbInfoCorrect"
GroupName="InfoQuestion"
cal:Message.Attach="ShouldProceed">
<RadioButton.Content>
<TextBlock Text="Yes" Foreground="White"/>
</RadioButton.Content>
</RadioButton>
<RadioButton Name="rbInfoNotCorrect"
GroupName="InfoQuestion"
cal:Message.Attach="ShouldStop">
<RadioButton.Content>
<TextBlock Text="No" Foreground="White"/>
</RadioButton.Content>
</RadioButton>
<Button x:Name="btnProceed" cal:Message.Attach="Proceed">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource WhiteButton}"/>
</Button.Style>
</Button>
<Button x:Name="btnStop" cal:Message.Attach="Stop">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource WhiteButton}"/>
</Button.Style>
</Button>
So when 'Yes' is checked, I want to change the 'Proceed' button style to BlueButton (another static resource) and when 'No' is checked, I want to change the 'Stop' button style to BlueButton. Of course this is part of a bigger problem so I just trying to be specific with the sample example.
The part I am stuck at is how to update the StaticResource from WhiteButton to BlueButton based on the radio button checked status. Any direction would be greatly appreciated.
Thanks.

You don't need to change the whole Style to do that. You can just add a simple DataTrigger to react directly to the Checkbox.IsChecked property. It's far simpler to declare the Styles like this instead:
<Style x:Key="ProceedButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=rbInfoCorrect}"
Value="True">
<Setter Property="Background" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="StopButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=rbInfoNotCorrect}"
Value="True">
<Setter Property="Background" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
Even if you want more properties to change, you can just declare the default ones as plain Setters and the ones triggered by the Checkbox.IsChecked property inside the DataTrigger. If you have lots of common properties in the two Styles, then you can still declare them all in one and base the other one on that one and just add the different DataTrigger.

We can replace the entire style using IMultiValue Converter.
For your requirement I came up with this example
public class StyleConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, CultureInfo culture)
{
if (values.Length < 1)
return Binding.DoNothing;
bool isCorrect = (bool)values[0];
bool isNotCorrect = (bool)values[1];
Style firstStyle = (Style)values[2];
Style secondStyle = (Style)values[3];
if (isCorrect)
return firstStyle;
if (isNotCorrect)
return secondStyle;
return Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
XAML
<Window x:Class="StackWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StackWpf"
Title="MainWindow" Name="window" Height="350" Width="525" >
<Window.Resources>
<ResourceDictionary>
<Style TargetType="Button" x:Key="WhiteStyle">
<Setter Property="Background" Value="White"/>
</Style>
<Style TargetType="Button" x:Key="BlueStyle">
<Setter Property="Background" Value="Blue"/>
</Style>
<local:StyleConverter x:Key="styleConverter"/>
</ResourceDictionary>
</Window.Resources>
<Grid>
<RadioButton Name="rbInfoCorrect" IsChecked="False"
GroupName="InfoQuestion" Margin="80,19,382,257">
<RadioButton.Content>
<TextBlock Text="Yes" Foreground="Black"/>
</RadioButton.Content>
</RadioButton>
<RadioButton Name="rbInfoNotCorrect" IsChecked="False"
GroupName="InfoQuestion" Margin="80,38,391,257">
<RadioButton.Content>
<TextBlock Text="No" Foreground="Black"/>
</RadioButton.Content>
</RadioButton>
<Button Content="Button" Margin="80,114,294,161">
<Button.Style>
<MultiBinding Converter="{StaticResource styleConverter}">
<Binding ElementName="rbInfoCorrect"
Path="IsChecked" />
<Binding ElementName="rbInfoNotCorrect"
Path="IsChecked" />
<Binding Source="{StaticResource WhiteStyle}" />
<Binding Source="{StaticResource BlueStyle}" />
</MultiBinding>
</Button.Style>
</Button>
</Grid>
</Window>
I have used this good article http://social.msdn.microsoft.com/Forums/vstudio/en-US/b25973bb-9e9c-4a99-8234-39a042e0a478/apply-styles-dynamically-to-buttons-in-xaml?forum=wpf earlier to tackle my issue.

I'm not sure if you can replace the complete Style but you can user a DataTrigger to change some properties of the button:
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource WhiteButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=rbInfoCorrect, Path=IsChecked}" Value="True">
<Setter Property="Background" Value="White" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=rbInfoCorrect, Path=IsChecked}" Value="False">
<Setter Property="Background" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>

Check out http://Globalizer.codeplex.com.
It switches out the entire style when it switches a language.
You basically look up the style in the resource dictionary, kill it and load a new one.

Related

Change property of controls child object by using Styles or DataTemplate in WPF application

Let's say I have a button and I have an image (though it could be any controls) inside of it:
<Button Width="150" Height="80">
<Image Source="..." Width="50" Height="50" />
</Button>
I want to change the style of button when mouse is over it and make it so that I could also change properties of the image inside when it happens.
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.5" />
<!-- Here I want to change alignment of the image inside the button if there is one -->
<Setter Property="Image.HorizontalAlignment" Value="Right" />
</Trigger>
</Style.Triggers>
</Style>
But it doesn't work this way, and for some reason any child controls start to change alignment, not only images but also text and other controls. The other things I tried just didn't compile. Probably DataTemplate should be used; I'm new to WPF and XAML and I still don't understand it enough and couldn't find what I need yet.
You should use HorizontalContentAlignment to set the content alignment of a button:
<Setter Property="HorizontalContentAlignment" Value="Right" />
Based on your comment below, I can give an example:
<Button Grid.Row="2" Width="150" Height="80">
<DockPanel Height="80" Width="150"><!-- A more complex control here-->
<Image Width="50" Height="50">
<Image.Source>
<BitmapImage DecodePixelWidth="50" UriSource="https://www.gravatar.com/avatar/9eae4ae63d70142e81f0365de42474ae?s=32&d=identicon&r=PG&f=1" />
</Image.Source>
</Image>
</DockPanel>
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</Style.Triggers>
<Style.Resources>
<Style TargetType="Image"><!-- The style target to the image control only in the button control -->
<Style.Triggers>
<!-- Binding to IsMouseOver of the button-->
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" Value="True">
<Setter Property="HorizontalAlignment" Value="Right" />
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
</Button.Style>
</Button>

Using style triggers on a static resource style to change more than properties

I am using Material Design XAML and I am trying to set a togglebutton icon and background color to something else when checked.
RED BOX CODE
<ToggleButton ToolTip="MaterialDesignFlatPrimaryToggleButton"
IsChecked="False"
Grid.Column="2"
Margin="78,58,99,52"
Grid.Row="1">
<Style TargetType="ToggleButton"
BasedOn="{StaticResource MaterialDesignFlatPrimaryToggleButton}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="Green" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton>
GREEN BOX CODE
<ToggleButton Style="{StaticResource MaterialDesignFlatPrimaryToggleButton}"
ToolTip="MaterialDesignFlatPrimaryToggleButton"
IsChecked="False"
Grid.ColumnSpan="2"
Grid.Column="3"
Margin="205,58,188,52"
Grid.Row="1">
<md:PackIcon Kind="WindowClose"
Foreground="Red"
Height="21"
Width="21"/>
</ToggleButton>
I was thinking I could use the basedon attribute to reserve the style with material design...if possible.
I am trying reserve the style and change the icon and set background color when checked to look like this:
How would I do this?
You are currently setting the Style as the ToggleButton.Content.
You've got to define the Style nested into the ToggleButton.Style property:
<ToggleButton ToolTip="MaterialDesignFlatPrimaryToggleButton"
IsChecked="False"
Grid.Column="2"
Margin="78,58,99,52"
Grid.Row="1">
<ToggleButton.Style>
<Style TargetType="ToggleButton"
BasedOn="{StaticResource MaterialDesignFlatPrimaryToggleButton}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="Green" />
<Setter Property="Content">
<Setter.Value>
<md:PackIcon Kind="SmileyHappy" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>

How to Write DataTrigger to update the value of a Tag Property in a WPF TextBox?

I need to Write DataTrigger to update the value of a Tag Property in a WPF TextBox.
If the TextBox Text.Count >0 then update the Tag property to True otherwise False.
XAML Source Code:
<TextBox Text="WPF" Tag="True">
<TextBox.Triggers>
<DataTrigger Property="Text" Value="0">
<Setter Property="Tag" Value="False" />
</DataTrigger>
</TextBox.Triggers>
</TextBox>
Your code won't work because you can't put data triggers into a control's Triggers collection. What you actually need is a trigger in the control's Style.
Try this instead:
<TextBox Text="WPF" Tag="True">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Value="0"
Binding="{Binding Text.Length, RelativeSource={RelativeSource Self}}">
<Setter Property="Tag" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Note that this is not foolproof: if the text box contains only whitespace for example, then it may appear to be empty but the length of the text will be greater than zero.
As the answers from user2946329 and ATM show, there are various ways of doing this in a <Style> trigger.
DataTrigger has not the property. You shoud use Property trigger for this purpose like this:
<TextBox Text="WPF" Tag="True">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Text" Value="0">
<Setter Property="Tag" Value="False" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Or if you want to change the Tag based on text Length you should try this:
<Trigger Property="Text" Value="">
I've used StevenRands answer and adapted my own:
In this example Tag will be false if Text is null or empty.
<StackPanel>
<TextBox Text="WPF" Name="tb">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Tag" Value="True"/>
<Style.Triggers>
<DataTrigger Value="" Binding="{Binding Text, RelativeSource={RelativeSource Self}}">
<Setter Property="Tag" Value="False" />
</DataTrigger>
<DataTrigger Value="{x:Null}" Binding="{Binding Text, RelativeSource={RelativeSource Self}}">
<Setter Property="Tag" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<!-- YOU CAN CHECK THE TAG'S VALUE HERE-->
<TextBlock Text="{Binding ElementName=tb, Path=Tag}"/>
</StackPanel>
And here's StevenRands better answer with some changes to make it work:
<TextBox Text="WPF">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Tag" Value="True"/>
<Style.Triggers>
<DataTrigger Value="0" Binding="{Binding Text.Length, RelativeSource={RelativeSource Self}}">
<Setter Property="Tag" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
You will have to do something similar to this:
Here I described a style and attached it to a control.
<Style TargetType="telerik:BarIndicator" x:Key="Percent">
<Style.Resources>
<vc:LoadPercentValueConverter x:Key="LPValueConverter"/>
</Style.Resources>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=myEngine.PercentLoaded, Converter={StaticResource LPValueConverter}}" Value="1" >
<Setter Property="Background" Value="Red"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=myEngine.PercentLoaded, Converter={StaticResource LPValueConverter}}" Value="0" >
<Setter Property="Background" Value="Green"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
Here is the control:
<telerik:BarIndicator Style="{StaticResource Percent}" Visibility="{Binding WhileLoading}" Value="{Binding Path=myEngine.PercentLoaded}" StartWidth="0.13"/>
And you have to use a value converter. Here is mine.
class LoadPercentValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
long percent = (long)System.Convert.ChangeType(value, typeof(long));
if (percent > 80)
{
return 1;
}
else
{
return 0;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

Creating a ToolTip that shows all Validation.Errors for a control using INotifyDataErrorInfo in WPF 4.5

I have multiple controls including a TextBox and a ComboBox and I would like all of them to display a ToolTip with all of the errors contained in the Validation.Errors collection. I would like them all to share a common style if possible, which is what I am trying. I am convinced I am doing something wrong with my binding in the ToolTip setter, but I can't figure out what. I return an Error object in my INotifyDataErrorInfo implementation that specifies the severity of an error (Error or Warning).
I would like to have a style that applies to all controls in the Window that would display a ToolTip containing a list of all errors and warnings for that control. The errors should be displayed in red and the warnings in yellow. Here is the Style I have come up with:
<Style TargetType="FrameworkElement">
<Setter Property="ToolTip">
<Setter.Value>
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors), RelativeSource={RelativeSource Self}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent.ErrorMessage}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
Value="{x:Static local:ErrorType.Warning}">
<Setter Property="Foreground" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(Validation.HasError)}" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent.ErrorMessage}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
Value="{x:Static local:ErrorType.Warning}">
<Setter Property="Foreground" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
I have tried changing the RelativeSource to search for an AncestoryType of Control at both AncestorLevel 1 and 2. None of this seems to work.
I based the style on a ControlTemplate that I used for the ErrorTemplate that does pretty much the same thing: it displays a red or yellow border depending on the error severity and displays a ToolTip exactly like what I want to do for the ToolTip on the control itself. I'm certain it has something to do with my binding, because the ErrorTemplate automatically has its DataContext set to the Validation.Errors collection, which makes it easy to bind the ItemsSource for the ItmesCollection. The ToolTip for the style has no such luck. Here is the working ControlTemplate I used for my ErrorTemplate:
<ControlTemplate x:Key="ErrorTemplate">
<Border BorderThickness="1">
<AdornedElementPlaceholder Name="ElementPlaceholder"/>
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ElementPlaceholder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent.ErrorSeverity}"
Value="{x:Static local:ErrorType.Warning}">
<Setter Property="BorderBrush" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Border.ToolTip>
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent.ErrorMessage}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
Value="{x:Static local:ErrorType.Warning}">
<Setter Property="Foreground" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border.ToolTip>
</Border>
</ControlTemplate>
Can anyone give me any suggestions?
This could be achieved much easier.
If you write the binding to "Tooltip" as above:
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors), Converter={StaticResource ErrorCollectionConverter}}">
</Setter>
</Trigger>
The Binding "miraculously" actually rebinds itself to the "PlacementTarget" of the tooltip. Thus to the control it is attached.
If you need to display the full list of items you can do the below:
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}" DisplayMemberPath="ErrorContent" />
</ToolTip>
</Setter.Value>
</Setter>
</Trigger>
You could even drop the Tooltip object and bind to the PlacementTarget directly from the ItemsControl. Then just use the Tooltip as the RelativeSource via AncestorType on the ItemsControl.
Hope this helps :)
After having tried to figure this out for quite some time, I finally stumbled on a post on the MSDN forums that led me down the right path. First of all, I needed to specify Styles for each TargetType that I wanted and base them on the original. Secondly, I realized that the problem was not in my binding, but in the fact that the collection that was bound to was not being updated. I have no idea why my ListBox/ItemsControl was not being updated when specified in XAML, but it does work if you specify it in a converter. Here is my new Style:
<Style TargetType="Control" x:Key="ErrorToolTip">
<Style.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock Text="{Binding ErrorContent.ErrorMessage}"
Background="Transparent">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
Value="{x:Static local:ErrorType.Warning}">
<Setter Property="Foreground" Value="Orange" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors), Converter={StaticResource ErrorCollectionConverter}}">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource ErrorToolTip}"/>
<Style TargetType="ComboBox" BasedOn="{StaticResource ErrorToolTip}"/>
And here is my converter function:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return null;
return new ListBox
{
ItemsSource = (ReadOnlyObservableCollection<ValidationError>) value,
BorderThickness = new Thickness(0),
Background = Brushes.Transparent
};
}
I hope this is helpful to any others out there that are having my same problem. If someone knows why this makes such a big difference, I would love to know.
This is just a more simplified version of Matts answer that I used. It works only for controls of type TextBox and does not use an error severity.
I used for a case when I needed to display one or more errors in context of a directory path entered by the user. In contrast to Matts answer I used
DisplayMemberPath = "ErrorContent"
to access the errors directly in the converter.
A style for a TextBox which shows the tooltip, when the attached property Validation.HasError is true:
<UserControl.Resources>
<ui:ErrorCollectionConverter x:Key="ErrorCollectionConverter"></ui:ErrorCollectionConverter>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors), Converter={StaticResource ErrorCollectionConverter}}">
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
My "Directory" TextBox implicitly using the style:
<TextBox Text="{Binding Directory, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}"></TextBox>
The value converter directly accessing the ErrorContent property:
internal class ErrorCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return null;
return new ListBox
{
ItemsSource = (ReadOnlyObservableCollection<ValidationError>)value,
BorderThickness = new Thickness(0),
Background = Brushes.Transparent,
DisplayMemberPath = "ErrorContent"
};
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

ToggleButton Style only works on last ToggleButton

I'm trying to customize my ToggleButtons so that when checked they say 'Yes' in green and when not checked, say 'No' in red.
I've created the following style which is sitting in my Styles resource dictionary.
<!-- ToggleButtons -->
<Style x:Key="YesNoToggleStyle" TargetType="ToggleButton">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="SpringGreen" />
<Setter Property="Content">
<Setter.Value>
<TextBlock Text="Yes"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Background" Value="Crimson" />
<Setter Property="Content">
<Setter.Value>
<TextBlock Text="No"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
This works ... sort of. If the ToggleButton is the last one of either value, then it displays correctly. All previous buttons with the same value are blank. The height was also shrinking, but I fixed that with the 'Height' Setter above the triggers. To illustrate, when a new record is being created it looks like:
and after I've clicked buttons 1, 2, and 3 and 1 again:
I originally had the style referenced from the surrounding grid:
<Grid>
...
<Grid.Resources>
<Style BasedOn="{StaticResource YesNoToggleStyle}" TargetType="{x:Type ToggleButton}" />
</Grid.Resources>
But changing that so each ToggleButton references the style individually (<ToggleButton Style="{StaticResource YesNoToggleStyle}" ... />) hasn't made a difference.
I looked at Customizing the toggle state of a toggle button in wpf, and Override ToggleButton Style where the effect is the same, but they talk about external images, and my issues is all within wpf.
I also looked at the second answer to: i want to change backcolor of toggle button when toggle button ischecked and viceversa in WPF but a) I only have the blend + sketchflow preview that comes with VS2012, and b) i'm a total noob with blend and can't get from Select the "Checked State" to Reset the Background Color instruction in the answer (plus i'd be surprised if this task requires the blend tool).
Can anyone show me what to do to get multiple ToggleButtons to use the same style properly?
This works for me. Somewhere in Dictionary1.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="YesNoToggleStyle" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource {x:Static ToolBar.ToggleButtonStyleKey}}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Background" Value="Crimson" />
<Setter Property="Content" Value="No"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="SpringGreen" />
<Setter Property="Content" Value="Yes"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
Note, that style is based on ToolBar.ToggleButtonStyle.
<Grid>
<Grid.Resources>
<ResourceDictionary Source="pack://application:,,,/Dictionary1.xaml"/>
</Grid.Resources>
<ItemsControl ItemContainerStyle="{StaticResource YesNoToggleStyle}">
<ToggleButton />
<ToggleButton />
<ToggleButton />
</ItemsControl>
</Grid>
try to replace Content property to ContentTemplate:
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="Yes"/>
</DataTemplate>
</Setter.Value>
</Setter>
In my case I wanted to have a "Locked" ToggleButton in a common dll defined and reused across my Apps.
Here's my result, which worked for me. Maybe someone find it useful (put this in a Resourcedictionary.xaml):
<BitmapImage x:Key="LockedLock"
UriSource="/...;component/Resources/Lock_closed_16p.png" />
<BitmapImage x:Key="OpenLock"
UriSource="/...;component/Resources/Lock_open_16p.png" />
<Style x:Key="LockButton"
TargetType="ToggleButton">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{DynamicResource OpenLock }"
Width="12"
Height="12"
Name="contentimage" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ToggleButton , AncestorLevel=1, Mode=FindAncestor }, Path=IsChecked}"
Value="True">
<Setter Property="Image.Source"
TargetName="contentimage"
Value="{DynamicResource LockedLock }" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Credits to:
Setting Button's Content to <Image> via Styles
Setter Target Name not recognized

Categories