ToggleButton changing image depending on state
Sir Ed Gonzalez, thank you for good example.
The only problem is that the binding to the MyToggleButton.IsChecked dependency property doesn't work properly (platform: Windows 7., NET 4.0, VS2010). So I have made some changes in your example.
xaml:
<ToggleButton x:Class="MyApp.ToggleButtonEx"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Checked="ToggleButton_CheckedChanged"
Unchecked="ToggleButton_CheckedChanged"
IsEnabledChanged="ToggleButton_IsEnabledChanged"
Loaded="ToggleButton_Loaded">
<Image x:Name='ButtonImage'/>
</ToggleButton>
cs:
public partial class ToggleButtonEx : ToggleButton
{
public ToggleButtonEx()
{
InitializeComponent();
}
public static readonly DependencyProperty EnabledUncheckedProperty =
DependencyProperty.Register(
"EnabledUnchecked",
typeof(ImageSource),
typeof(ToggleButtonEx),
new PropertyMetadata(onEnabledUncheckedChangedCallback));
public ImageSource EnabledUnchecked
{
get { return (ImageSource)GetValue(EnabledUncheckedProperty); }
set { SetValue(EnabledUncheckedProperty, value); }
}
static void onEnabledUncheckedChangedCallback(
DependencyObject dobj,
DependencyPropertyChangedEventArgs args)
{
//do something if needed
}
public static readonly DependencyProperty DisabledUncheckedProperty =
DependencyProperty.Register(
"DisabledUnchecked",
typeof(ImageSource),
typeof(ToggleButtonEx),
new PropertyMetadata(onDisabledUncheckedChangedCallback));
public ImageSource DisabledUnchecked
{
get { return (ImageSource)GetValue(DisabledUncheckedProperty); }
set { SetValue(DisabledUncheckedProperty, value); }
}
static void onDisabledUncheckedChangedCallback(
DependencyObject dobj,
DependencyPropertyChangedEventArgs args)
{
//do something if needed
}
public static readonly DependencyProperty EnabledCheckedProperty =
DependencyProperty.Register(
"EnabledChecked",
typeof(ImageSource),
typeof(ToggleButtonEx),
new PropertyMetadata(onEnabledCheckedChangedCallback));
public ImageSource EnabledChecked
{
get { return (ImageSource)GetValue(EnabledCheckedProperty); }
set { SetValue(EnabledCheckedProperty, value); }
}
static void onEnabledCheckedChangedCallback(
DependencyObject dobj,
DependencyPropertyChangedEventArgs args)
{
//do something if needed
}
private void ToggleButton_CheckedChanged(object sender, RoutedEventArgs e)
{
ChangeImage();
}
private void ToggleButton_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
ChangeImage();
}
private void ToggleButton_Loaded(object sender, RoutedEventArgs e)
{
ChangeImage();
}
private void ChangeImage()
{
if (IsEnabled)
{
if(IsChecked == true)
ButtonImage.Source = EnabledChecked;
else
ButtonImage.Source = EnabledUnchecked;
}
else
{
ButtonImage.Source = DisabledUnchecked;
}
}
}
Usage pattern remains unchaged:
<local:MyToggleButton
IsChecked='True'
IsEnabled='False'
EnabledChecked='<add your image source here>'
EnabledUnchecked='<add your image source here>'
DisabledUnchecked='<add your image source here>'/>
This solution is a simple one:
<ToggleButton IsChecked="{Binding IsCheckedState}">
<Image Width="24" Height="24" >
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsCheckedState}" Value="true">
<Setter Property="Source" Value="Images/checked.ico"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsCheckedState}" Value="false">
<Setter Property="Source" Value="Images/unchecked.ico"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ToggleButton>
You can get the functionality you want by creating a UserControl that exposes dependency properties for Command, IsChecked, and one for each stateful image. Your user control will contain a toggle button and image.
You can use MultiDataTriggers to detect your state and swtich the image depending on the state.
Because you exposed the DependencyProperties for the stateful images, they can be set using Databinding wherever you declare your control. The triggers will automatically switch the image source for you, once state changes.
[Edit: Added some code to help explain]
Here is a partial example to get you started:
MyToggleButton.xaml:
<UserControl x:Class="ToggleTest.MyToggleButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ToggleButton
IsChecked='{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ToggleButton} },
Path=IsChecked}'>
<Image
x:Name='ButtonImage'>
<Image.Style>
<Style
TargetType='{x:Type Image}'>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition
Binding='{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ToggleButton} },
Path=IsChecked}'
Value='True' />
<Condition
Binding='{Binding
RelativeSource={RelativeSource Self},
Path=IsEnabled}'
Value='True' />
</MultiDataTrigger.Conditions>
<Setter
Property='Source'
Value='{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl} },
Path=EnabledChecked}' />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition
Binding='{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ToggleButton} },
Path=IsChecked}'
Value='False' />
<Condition
Binding='{Binding
RelativeSource={RelativeSource Self},
Path=IsEnabled}'
Value='True' />
</MultiDataTrigger.Conditions>
<Setter
Property='Source'
Value='{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl} },
Path=EnabledUnchecked}' />
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition
Binding='{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ToggleButton} },
Path=IsChecked}'
Value='False' />
<Condition
Binding='{Binding
RelativeSource={RelativeSource Self},
Path=IsEnabled}'
Value='False' />
</MultiDataTrigger.Conditions>
<Setter
Property='Source'
Value='{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl} },
Path=DisabledUnchecked}' />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ToggleButton>
And the cs file:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace ToggleTest
{
/// <summary>
/// Interaction logic for ToggleButton.xaml
/// </summary>
public partial class MyToggleButton : UserControl
{
public MyToggleButton()
{
InitializeComponent();
}
public static readonly DependencyProperty EnabledUncheckedProperty =
DependencyProperty.Register(
"EnabledUnchecked",
typeof(ImageSource),
typeof(MyToggleButton),
new PropertyMetadata(onEnabledUncheckedChangedCallback));
public ImageSource EnabledUnchecked
{
get { return (ImageSource)GetValue(EnabledUncheckedProperty); }
set { SetValue(EnabledUncheckedProperty, value); }
}
static void onEnabledUncheckedChangedCallback(
DependencyObject dobj,
DependencyPropertyChangedEventArgs args)
{
//do something if needed
}
public static readonly DependencyProperty DisabledUncheckedProperty =
DependencyProperty.Register(
"DisabledUnchecked",
typeof(ImageSource),
typeof(MyToggleButton),
new PropertyMetadata(onDisabledUncheckedChangedCallback));
public ImageSource DisabledUnchecked
{
get { return (ImageSource)GetValue(DisabledUncheckedProperty); }
set { SetValue(DisabledUncheckedProperty, value); }
}
static void onDisabledUncheckedChangedCallback(
DependencyObject dobj,
DependencyPropertyChangedEventArgs args)
{
//do something if needed
}
public static readonly DependencyProperty EnabledCheckedProperty =
DependencyProperty.Register(
"EnabledChecked",
typeof(ImageSource),
typeof(MyToggleButton),
new PropertyMetadata(onEnabledCheckedChangedCallback));
public ImageSource EnabledChecked
{
get { return (ImageSource)GetValue(EnabledCheckedProperty); }
set { SetValue(EnabledCheckedProperty, value); }
}
static void onEnabledCheckedChangedCallback(
DependencyObject dobj,
DependencyPropertyChangedEventArgs args)
{
//do something if needed
}
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register(
"IsChecked",
typeof(Boolean),
typeof(MyToggleButton),
new PropertyMetadata(onCheckedChangedCallback));
public Boolean IsChecked
{
get { return (Boolean)GetValue(IsCheckedProperty); }
set { if(value != IsChecked) SetValue(IsCheckedProperty, value); }
}
static void onCheckedChangedCallback(
DependencyObject dobj,
DependencyPropertyChangedEventArgs args)
{
//do something, if needed
}
}
}
This control could be used like so:
<local:MyToggleButton
IsChecked='True'
IsEnabled='False'
EnabledChecked='<add your image source here>'
EnabledUnchecked='<add your image source here>'
DisabledUnchecked='<add your image source here>'/>