paraJdox1
paraJdox1

Reputation: 973

How to change radio button's toggle button to an image in wpf (for grouped radio buttons)?

I change my radio button's image (when clicked or not) in a ResourceDictionary like this:

<Style TargetType="{x:Type RadioButton}"
        x:Key="MenuButtonTheme">
    <Style.Setters>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="RadioButton">
                    <Grid Background="{TemplateBinding Background}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto" />
                            <ColumnDefinition Width="auto" />
                        </Grid.ColumnDefinitions>
                        <Image x:Name="SidebarRadioButtonMenuIcon"
                                Source="/UiDesign/Images/SidebarIcons/logout.png"
                                Width="18.57"
                                Height="18.57"
                                Grid.Column="0" />
                        <TextBlock x:Name="SidebarRadioButtonMenuText"
                                    Text="{TemplateBinding Property=Content}"
                                    VerticalAlignment="Center"
                                    Foreground="#7D8083"
                                    FontSize="14.59"
                                    FontWeight="Bold"
                                    FontFamily="/UiDesign/Fonts/#Nunito"
                                    Margin="12,0,0,0"
                                    Grid.Column="1" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked"
                                    Value="True">
                            <Setter TargetName="SidebarRadioButtonMenuText"
                                    Property="Foreground"
                                    Value="#F54342" />
                            <Setter TargetName="SidebarRadioButtonMenuIcon"
                                    Property="Source"
                                    Value="/UiDesign/Images/SidebarIcons/Selected/logout.png" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Background"
                Value="Transparent" />
    </Style.Setters>
</Style>

The code above is working just fine. But my menu consists of more than 1 radio buttons.

This is how I apply my style:

<RadioButton Content="Dashboard"
             Grid.Column="1"
             Grid.Row="0"
             Style="{StaticResource MenuButtonTheme}" />

This is how my buttons look like:

enter image description here


When I select a menu item, it will look like this:

enter image description here

enter image description here

(the images for IsChecked true and false are all the same for all my menu items (which are RadioButtons))

The question is, do I have to create a ResourceDictionary for each button so that their image will change when I select on them (and of course, change their default image)?


This is want I want to achieve:

enter image description here

enter image description here

Upvotes: 0

Views: 479

Answers (2)

emoacht
emoacht

Reputation: 3556

There are a variety of ways to accomplish this but I think the straightforward way is to define a custom RadioButton which has dependency properties for URI strings to images for different states and bind them from XAML.

Let's say, we create SampleRadioButton which has NormalImageUriString and CheckedImageUriString dependency properties and a converter for converting URI string to BitmapImage.

public class SampleRadioButton : RadioButton
{
    public string NormalImageUriString
    {
        get { return (string)GetValue(NormalImageUriStringProperty); }
        set { SetValue(NormalImageUriStringProperty, value); }
    }
    public static readonly DependencyProperty NormalImageUriStringProperty =
        DependencyProperty.Register("NormalImageUriString", typeof(string), typeof(SampleRadioButton), new PropertyMetadata(null));

    public string CheckedImageUriString
    {
        get { return (string)GetValue(CheckedImageUriStringProperty); }
        set { SetValue(CheckedImageUriStringProperty, value); }
    }
    public static readonly DependencyProperty CheckedImageUriStringProperty =
        DependencyProperty.Register("CheckedImageUriString", typeof(string), typeof(SampleRadioButton), new PropertyMetadata(null));
}

public class ImageUriStringConverver : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is not string source)
            return DependencyProperty.UnsetValue;

        return new BitmapImage(new Uri(source, UriKind.Relative));
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

And edit XAML to bind these dependency properties using the converter.

<local:ImageUriStringConverver x:Key="ImageUriStringConverterKey"/>

<Style TargetType="{x:Type local:SampleRadioButton}">
    <Setter Property="NormalImageUriString" Value="[URI string to default image for normal state]"/>
    <Setter Property="CheckedImageUriString" Value="[URI string to default image for checked state]"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:SampleRadioButton}">
                <Grid Background="{TemplateBinding Background}">
                    ...
                    <Image x:Name="SidebarRadioButtonMenuIcon"
                           Source="{TemplateBinding NormalImageUriString, Converter={StaticResource ImageUriStringConverterKey}}"
                           ...
                           />
                    <TextBlock x:Name="SidebarRadioButtonMenuText"
                               ...
                               />
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsChecked" Value="True">
                        <Setter TargetName="SidebarRadioButtonMenuText" Property="Foreground" Value="#F54342" />
                        <Setter TargetName="SidebarRadioButtonMenuIcon" Property="Source" Value="{Binding CheckedImageUriString, RelativeSource={RelativeSource AncestorType={x:Type local:SampleRadioButton}}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Then we can set specific images by setting these dependency properties in each SampleRadioButton.

<local:SampleRadioButton Content="Sample"
                         NormalImageUriString="[URI string to specific image for normal state]"
                         CheckedImageUriString="[URI string to specific image for checked state]"/>

Upvotes: 2

Ozgur Saklanmaz
Ozgur Saklanmaz

Reputation: 564

In this case, I think there is no need to change the image in the case of IsChecked. I linked the picture above to the RadioButton Tag (I did it quickly, you can link it to something more convenient.)

You can now use Tag as image address path in your own xaml code.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Style TargetType="{x:Type RadioButton}"
    x:Key="MenuButtonTheme">
    <Style.Setters>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="RadioButton">
                    <Grid Background="{TemplateBinding Background}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto" />
                            <ColumnDefinition Width="auto" />
                        </Grid.ColumnDefinitions>
                        <Image x:Name="SidebarRadioButtonMenuIcon"
                            Source="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"
                            Width="18.57"
                            Height="18.57"
                            Grid.Column="0" />
                        <TextBlock x:Name="SidebarRadioButtonMenuText"
                                Text="{TemplateBinding Property=Content}"
                                VerticalAlignment="Center"
                                Foreground="#7D8083"
                                FontSize="14.59"
                                FontWeight="Bold"
                                FontFamily="/UiDesign/Fonts/#Nunito"
                                Margin="12,0,0,0"
                                Grid.Column="1" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked"
                                Value="True">
                            <Setter TargetName="SidebarRadioButtonMenuText"
                                Property="Foreground"
                                Value="#F54342" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Background"
            Value="Transparent" />
    </Style.Setters>
</Style>

MainWindow.xaml

            <RadioButton Content="Dashboard"
         Grid.Column="1"
         Grid.Row="0"
         Style="{StaticResource MenuButtonTheme}" 
         Tag="/Images/image2.png">
        </RadioButton>

Upvotes: 0

Related Questions