Programmatically changing button icon in WPF

Solution 1:

You can accomplish this by changing the content of the button, through an event handler.

You can set both the "Play" Icon and "Stop" Icon as a resource, under Window.Resources like so:

<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">
<Window.Resources>
    <Image x:Key="Play" Source="/WpfApplication1;component/Play_Icon.png" Height="50" Width="50" />
    <Image x:Key="Stop" Source="/WpfApplication1;component/Stop_Icon.png" Height="50" Width="50"/>
</Window.Resources>
<Grid>
    <Button Click="Button_Click" Name="MediaButton">
        <DynamicResource ResourceKey="Play"/>
    </Button>
</Grid>

Now, when the button is clicked, you can simply change the button's content to a different resource (the stop icon). In the button's event handler, you can do this:

C#

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (MediaButton.Content == FindResource("Play"))
    {
        MediaButton.Content = FindResource("Stop");
    }
    else
    {
        MediaButton.Content = FindResource("Play");
    }
}

Edit: Shorter notation

MediaButton.Content = FindResource(MediaButton.Content == FindResource("Play") ? "Stop" : "Play");

Hope this helps, let me know if you have any more questions.

Solution 2:

If you have your image definition something like this:

<Image Source="{Binding ImageSource}" Stretch="Fill"/>

Then in your code where you want to do the switch simply have:

ImageSource = image;

where image is defined as:

image = new BitmapImage(new Uri("/Application;component/Resources/pause.png", UriKind.Relative));

Of course it does rely on you using the MVVM pattern and implementing the INotifyPropertyChanged interface in your code.

Solution 3:

Use a DataTrigger (edit) in the Image's Style (/edit) on the change condition:

<Button Height="69" HorizontalAlignment="Left" Margin="-2,0,0,0" Name="toggleBroadcast" VerticalAlignment="Top" Width="64" Grid.Row="1" Opacity="0.5" Click="changeBroadcastState_Click">
    <Image>
        <Image.Style>        
            <Style TargetType="{x:Type Image}">
                <Setter Property="Source" Value="Images\playIcon.png" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding myCondition}" Value="True">
                        <Setter Property="Source" Value="Images\stopIcon.png" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Image.Style>        
    </Image>
</Button>

The myCondition variable would then be a boolean property in your ViewModel (or, more general, the Control's DataContext), something like

public bool myCondition { get { return ([whatever that condition might be]); } }

This may also include a setter and could as well be a simple auto property. As with the other MVVM answer, it will rely on the ViewModel to implement INotifyPropertyChanged.

The nice thing is, once the condition is no longer fulfilled, the DataTrigger will automatically set the Source property back to its original value.

Disclaimer: I have no way to test that right now, so take this with a grain of salt and probably some debugging effort...