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>'/>