I needed a button with text and icon that did two things:
- Text and icon went grey if the button was disabled.
- Icon changes depending on Boolean property (e.g. connected / disconnected).
For the icon I used the XAML icons from here: http://modernuiicons.com/
An example of an icon is:
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="appbar_connect"
Width="76"
Height="76"
Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path
Width="36.7542"
Height="36.7542"
Canvas.Left="19.6229"
Canvas.Top="19.6229"
Stretch="Fill"
Fill="#FF000000"
Data="F1 M 25.7639,28.0031L 20.0866,22.3258C 19.4683,21.7075 19.4683,20.705 20.0866,20.0866C 20.705,19.4683 21.7075,19.4683 22.3258,20.0867L 28.0031,25.7639C 32.3443,22.5092 38.5302,22.856 42.4783,26.8042L 26.8041,42.4784C 22.856,38.5302 22.5092,32.3443 25.7639,28.0031 Z M 49.1958,33.5217C 53.144,37.4699 53.4908,43.6557 50.2361,47.9969L 55.9133,53.6742C 56.5317,54.2925 56.5317,55.295 55.9133,55.9134C 55.295,56.5317 54.2925,56.5317 53.6742,55.9134L 47.9969,50.2361C 43.6557,53.4908 37.4698,53.1441 33.5216,49.1959L 36.8804,45.8371L 34.0814,43.0381C 33.1539,42.1107 33.1539,40.6069 34.0814,39.6794C 35.0089,38.7519 36.5127,38.7519 37.4402,39.6794L 40.2392,42.4784L 42.4783,40.2392L 39.6794,37.4402C 38.7519,36.5127 38.7519,35.009 39.6794,34.0815C 40.6069,33.154 42.1106,33.154 43.0381,34.0815L 45.8371,36.8804L 49.1958,33.5217 Z "/>
</Canvas>
I put the icon in a resource dictionary, with some changes
- Wrapped in a
ControlTemplate
to make it usable more than once. - Gave it a key
- Unnecessary attributes removed
Fill
changed toFill="{Binding RelativeSource={RelativeSource AncestorType=Control}, Path=Foreground}"
. This solves the first issue, going grey when the button is disabled. The button will change it's foreground colour to grey when disabled, and so the icon will too. Furthermore, the icon can be changed in colour by changing the button foreground colour.
Code:
<ControlTemplate x:Key="ConnectButtonIconTemplate">
<Canvas
Width="76"
Height="76"
Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path
Width="36.7542"
Height="36.7542"
Canvas.Left="19.6229"
Canvas.Top="19.6229"
Stretch="Fill"
Fill="{Binding RelativeSource={RelativeSource AncestorType=Control}, Path=Foreground}"
Data="F1 M 25.7639,28.0031L 20.0866,22.3258C 19.4683,21.7075 19.4683,20.705 20.0866,20.0866C 20.705,19.4683 21.7075,19.4683 22.3258,20.0867L 28.0031,25.7639C 32.3443,22.5092 38.5302,22.856 42.4783,26.8042L 26.8041,42.4784C 22.856,38.5302 22.5092,32.3443 25.7639,28.0031 Z M 49.1958,33.5217C 53.144,37.4699 53.4908,43.6557 50.2361,47.9969L 55.9133,53.6742C 56.5317,54.2925 56.5317,55.295 55.9133,55.9134C 55.295,56.5317 54.2925,56.5317 53.6742,55.9134L 47.9969,50.2361C 43.6557,53.4908 37.4698,53.1441 33.5216,49.1959L 36.8804,45.8371L 34.0814,43.0381C 33.1539,42.1107 33.1539,40.6069 34.0814,39.6794C 35.0089,38.7519 36.5127,38.7519 37.4402,39.6794L 40.2392,42.4784L 42.4783,40.2392L 39.6794,37.4402C 38.7519,36.5127 38.7519,35.009 39.6794,34.0815C 40.6069,33.154 42.1106,33.154 43.0381,34.0815L 45.8371,36.8804L 49.1958,33.5217 Z "/>
</Canvas>
</ControlTemplate>
The button is laid out like:
<Button x:Name="buttonConnect" Command="{Binding StartCameraCommand}" Style="{StaticResource ConnectToolbarButtonStyle}">
<StackPanel>
<Viewbox>
<ContentControl />
</Viewbox>
<TextBlock/>
</StackPanel>
</Button>
The base button style is:
<Style x:Key="ToolbarButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Width" Value="65"/>
<Style.Resources>
<Style TargetType="{x:Type Viewbox}">
<Setter Property="Width" Value="40"/>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</Style.Resources>
</Style>
To make icon change according to a Boolean property, I added as style derived from it:
<Style x:Key="ConnectToolbarButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource ToolbarButtonStyle}">
<Style.Resources>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Template" Value="{StaticResource ConnectButtonIconTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding CameraConnected}" Value="False">
<Setter Property="Template" Value="{StaticResource ConnectButtonIconTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding CameraConnected}" Value="True">
<Setter Property="Template" Value="{StaticResource DisconnectButtonIconTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Text" Value="Connect"/>
<Style.Triggers>
<DataTrigger Binding="{Binding CameraConnected}" Value="True">
<Setter Property="Text" Value="Disconnect"/>
</DataTrigger>
<DataTrigger Binding="{Binding CameraConnected}" Value="False">
<Setter Property="Text" Value="Connect"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
One thing is that I have to put <Setter Property="HorizontalAlignment" Value="Center"/>
for the TextBlock
in the derived style, I guess it gets overwritten.
Note that buttons that do not change icon can be defined like this:
<Button x:Name="buttonRefresh" Click="buttonRefresh_Click" Style="{StaticResource ToolbarButtonStyle}">
<StackPanel>
<Viewbox>
<ContentControl Template="{StaticResource RefreshButtonIconTemplate}"/>
</Viewbox>
<TextBlock Text="Refresh"/>
</StackPanel>
</Button>
For these, I assume it would be possible to do away with the writing the Viewbox
and other child elements by using ControlTemplate
targeting the button and then change the text and icon using a style.
ConverterParameter
if you, rightly IMO, want to keep everything in XAML). Also, IMO, this might be a good chance to create a custom controlToolbarButton
. \$\endgroup\$