Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a custom WPF XAML style for check box images

Tags:

c#

wpf

xaml

I have a C# WPF Page and on it I have placed several small images that I want to act like check boxes (I have my own custom images for hover and selected states).

I am manually changing the images like so:

<Image x:Name="Image_Custom" Source="/Images/checkcircle_off.png" Width="16" Height="16" HorizontalAlignment="Left"  Margin="30,107,0,0" VerticalAlignment="Top" MouseEnter="Image_Custom_MouseEnter" MouseLeave="Image_Custom_MouseLeave" MouseUp="Image_Custom_MouseUp" MouseLeftButtonDown="Image_Custom_MouseLeftButtonDown"/>


    private void Image_Custom_MouseEnter(object sender, MouseEventArgs e)
    {
        if (_selected == false)
        {
            var uriSource = new Uri("/Images/checkcircle_hover.png", UriKind.Relative);
            Image_Custom.Source = new BitmapImage(uriSource);
        }
    }

    private void Image_Custom_MouseLeave(object sender, MouseEventArgs e)
    {
        if (_selected == false)
        {
            var uriSource = new Uri("/Images/checkcircle_off.png", UriKind.Relative);
            Image_Custom.Source = new BitmapImage(uriSource);
        }
    }

    private void Image_Custom_MouseUp(object sender, MouseButtonEventArgs e)
    {
        if (_selected)
        {
            var uriSource = new Uri("/Images/checkcircle_off.png", UriKind.Relative);
            Image_Custom.Source = new BitmapImage(uriSource);
            _selected = false;
        }
        else
        {
            var uriSource = new Uri("/Images/checkcircle_on.png", UriKind.Relative);
            Image_Custom.Source = new BitmapImage(uriSource);
            _selected = true;
        }
    }

    private void Image_Custom_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (_selected)
        {
            var uriSource = new Uri("/Images/checkcircle_off.png", UriKind.Relative);
            Image_Custom.Source = new BitmapImage(uriSource);
            _selected = false;
        }
        else
        {
            var uriSource = new Uri("/Images/checkcircle_on.png", UriKind.Relative);
            Image_Custom.Source = new BitmapImage(uriSource);
            _selected = true;
        }
    }

This works but is very cumbersome and I will have up to 20 check boxes.

How can I create a custom XAML Style that I can use for each image or something similar.

EDIT:

I have used the following style to handle the hover over:

<Page.Resources>
    <Style TargetType="Image" x:Key="checkBoxStyle">
        <Setter Property="Source" Value="/Images/checkcircle_off.png"/>
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Source" Value="/Images/checkcircle_hover.png"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</Page.Resources>

    <Image x:Name="Image_Custom" Style="{StaticResource checkBoxStyle}" Width="16" Height="16" HorizontalAlignment="Left"  Margin="30,107,0,0" VerticalAlignment="Top" MouseEnter="Image_Custom_MouseEnter" MouseLeave="Image_Custom_MouseLeave" MouseUp="Image_Custom_MouseUp" MouseLeftButtonDown="Image_Custom_MouseLeftButtonDown"/>

But I dont know how to handle the clicked event. How can I do this?

EDIT 2

I have did the following:

        <Style TargetType="{x:Type CheckBox}" x:Key="myCheckBoxStyle">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type CheckBox}">
                    <Image x:Name="checkBoxImage" Source="/Images/checkcircle_off.png"></Image>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter TargetName="checkBoxImage" Property="Source" Value="/Images/checkcircle_on.png"/>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="False">
                            <Setter TargetName="checkBoxImage" Property="Source" Value="/Images/checkcircle_off.png"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="checkBoxImage" Property="Source" Value="/Images/checkcircle_hover.png"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

<CheckBox Content="My CheckBox" Style="{StaticResource myCheckBoxStyle}" Width="16" Height="16" Foreground="white" FontSize="16" HorizontalAlignment="Left" Margin="30,242,0,0" VerticalAlignment="Top" />

The correct images appear when hovered, checked and unchecked.
But I noticed that the Content has disappeared ("My Checkbox") and also I only want the hover state to appear when its not checked, how can I do that?

like image 486
Harry Boy Avatar asked May 03 '14 14:05

Harry Boy


2 Answers

In WPF you generally look for a control that has the functionality you need and then you make it look like you want. So if you want CheckBox functionality then you use CheckBox control and change its Template to be what you want. So you can create Style for CheckBox that will set your custom Template

<Window.Resources>
    <Style TargetType="{x:Type CheckBox}" x:Key="myCheckboxStyle">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type CheckBox}">
                    <StackPanel Orientation="Horizontal">
                        <Image x:Name="checkboxImage" Source="normal.png" Width="32"/>
                        <ContentPresenter/>
                    </StackPanel>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter TargetName="checkboxImage" Property="Source" Value="checked.png"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsMouseOver" Value="True"/>
                                <Condition Property="IsChecked" Value="False"/>
                            </MultiTrigger.Conditions>
                            <Setter TargetName="checkboxImage" Property="Source" Value="hover.png"/>
                        </MultiTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

and then just use it on any CheckBox

<CheckBox Style="{StaticResource myCheckboxStyle}" Content="ABC"/>

and you'll have all CheckBox functionality with your custom looks

like image 99
dkozl Avatar answered Nov 11 '22 10:11

dkozl


If you override CheckBox and create a specific style this will look like this:

public class MyCheckBox : CheckBox
{

    #region ImageNormal

    /// <summary>
    /// ImageNormal Dependency Property
    /// </summary>
    public static readonly DependencyProperty ImageNormalProperty =
        DependencyProperty.Register("ImageNormal", typeof(ImageSource), typeof(MyCheckBox),
            new FrameworkPropertyMetadata((ImageSource)null));

    /// <summary>
    /// Gets or sets the ImageNormal property. This dependency property 
    /// indicates ....
    /// </summary>
    public ImageSource ImageNormal
    {
        get { return (ImageSource)GetValue(ImageNormalProperty); }
        set { SetValue(ImageNormalProperty, value); }
    }

    #endregion

    #region ImageChecked

    /// <summary>
    /// ImageChecked Dependency Property
    /// </summary>
    public static readonly DependencyProperty ImageCheckedProperty =
        DependencyProperty.Register("ImageChecked", typeof(ImageSource), typeof(MyCheckBox),
            new FrameworkPropertyMetadata((ImageSource)null));

    /// <summary>
    /// Gets or sets the ImageChecked property. This dependency property 
    /// indicates ....
    /// </summary>
    public ImageSource ImageChecked
    {
        get { return (ImageSource)GetValue(ImageCheckedProperty); }
        set { SetValue(ImageCheckedProperty, value); }
    }

    #endregion

    //... other image properties removed for simplicity

    static MyCheckBox()
    {
        //Override base class style
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCheckBox), new FrameworkPropertyMetadata(typeof(MyCheckBox)));
    }


}

Associated XAML Style:

<Style TargetType="{x:Type local:MyCheckBox}">
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type CheckBox}">
                <Grid>

                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="grdNormal">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="grdMouseOver">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="grdPressed">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="grdNormal">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled"/>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="CheckStates">
                            <VisualState x:Name="Checked">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgUnchecked1">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgChecked1">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgUnchecked2">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgChecked2">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgUnchecked3">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="imgChecked3">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Unchecked"/>
                            <VisualState x:Name="Indeterminate"/>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>

                    <Grid x:Name="grdNormal">
                        <Image x:Name="imgUnchecked1" Source="{Binding ImageNormal, RelativeSource={RelativeSource TemplatedParent}}"/>
                        <Image x:Name="imgChecked1" Visibility="Collapsed" Source="{Binding ImageNormal, RelativeSource={RelativeSource TemplatedParent}}"/>
                    </Grid>

                    <Grid x:Name="grdMouseOver" Visibility="Collapsed">
                        <Image x:Name="imgUnchecked2" Source="{Binding ImageMouseOver, RelativeSource={RelativeSource TemplatedParent}}"/>
                        <Image x:Name="imgChecked2" Visibility="Collapsed" Source="{Binding ImageMouseOverChecked, RelativeSource={RelativeSource TemplatedParent}}"/>
                    </Grid>

                    <Grid x:Name="grdPressed" Visibility="Collapsed">
                        <Image x:Name="imgUnchecked3" Source="{Binding ImagePressed, RelativeSource={RelativeSource TemplatedParent}}"/>
                        <Image x:Name="imgChecked3" Visibility="Collapsed" Source="{Binding ImagePressedChecked, RelativeSource={RelativeSource TemplatedParent}}"/>
                    </Grid>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
like image 1
Dmitry Avatar answered Nov 11 '22 10:11

Dmitry