Как создать пользовательский стиль WPF XAML для образов флажков

У меня есть страница C# WPF, и на ней я разместил несколько небольших изображений, которые я хочу действовать как флажки (у меня есть свои собственные изображения для наведения и выбранных состояний).

Я вручную меняю изображения следующим образом:

<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;
        }
    }

это работает, но очень громоздко, и у меня будет до 20 флажков.

как создать пользовательский стиль XAML, который я могу использовать для каждого изображения или чего-то еще подобный.

EDIT:

я использовал следующий стиль для обработки наведения:

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

но я не знаю, как обрабатывать события clicked. Как я могу это сделать?

правка 2

Я сделал следующее:

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

правильные изображения появляются при наведении, проверяемые и непроверяемые.
Но я заметил, что контент исчез ("мой флажок"), а также я хочу только наведение состояние появляется, когда его не проверено, как я могу это сделать?

2 ответов


в WPF вы обычно ищете элемент управления, который имеет необходимую функциональность, а затем вы делаете его похожим на то, что хотите. Так что если вы хотите CheckBox функциональности, то вы используете CheckBox управление и изменение его Template то, что вы хотите. Таким образом, вы можете создать Style на CheckBox это установит ваш пользовательский 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>

а затем просто используйте его на любом CheckBox

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

и у вас будет все CheckBox функциональность с вашими пользовательскими взглядами


Если вы переопределите флажок и создадите определенный стиль, это будет выглядеть так:

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)));
    }


}

связанный стиль XAML:

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