wpf中三态按钮实现

wpf中, 按钮需要切换开、关、无状态三种形式
大概思路是怎样的?

在 WPF 中实现三态按钮需要使用一些自定义代码。下面是一个大概的思路:

创建一个类继承自 Button,并为其添加一个依赖属性,来表示按钮的状态。
使用 DataTrigger 来监听这个依赖属性的变化,并根据变化来更改按钮的样式。
在按钮的事件处理程序中,更新按钮状态的依赖属性。
示例代码:

using System.Windows;
using System.Windows.Controls;

namespace WpfApp
{
    public class ThreeStateButton : Button
    {
        public static readonly DependencyProperty StateProperty =
            DependencyProperty.Register("State", typeof(int), typeof(ThreeStateButton), new PropertyMetadata(0));

        public int State
        {
            get { return (int)GetValue(StateProperty); }
            set { SetValue(StateProperty, value); }
        }

        static ThreeStateButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ThreeStateButton), new FrameworkPropertyMetadata(typeof(ThreeStateButton)));
        }
    }
}

XAML

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApp">
    <Style TargetType="{x:Type local:ThreeStateButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ThreeStateButton}">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="border">
                                            <EasingColorKeyFrame KeyTime="0" Value="{StaticResource MouseOverBrush}"/>
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard><ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="border">
                                            <EasingColorKeyFrame KeyTime="0" Value="{StaticResource PressedBrush}"/>
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="CheckStates">
                                <VisualState x:Name="Checked">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="checkMark">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unchecked">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="checkMark">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Collapsed}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Indeterminate">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="indeterminateMark">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="border"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                            <ContentPresenter x:Name="contentPresenter"
                                              Content="{TemplateBinding Content}"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              Margin="{TemplateBinding Padding}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                        <Path x:Name="checkMark"
                              Data="M0,123 L39,82 L124,164 L256,18 L295,57 L124,240 z"
                              Fill="{TemplateBinding Foreground}"
                              Visibility="Collapsed"
                              Stretch="Uniform"
                              StrokeThickness="1"
                              IsHitTestVisible="False"
                              HorizontalAlignment="Right"
                              VerticalAlignment="Center"
                              Margin="4"/>
                        <Path x:Name="indeterminateMark"
                              Data="M0,0 L50,50 M50,0 L0,50"
                              Visibility="Collapsed"
                              Stretch="Uniform"
                              Stro


接下来是在 XAML 中使用这个三态按钮的示例:


<local:ThreeStateButton State="{Binding MyButtonState}" Content="My Three State Button" Click="ThreeStateButton_Click"/>

在这里,我们绑定了按钮的 State 属性到一个名为 MyButtonState 的属性上。在按钮被点击时,我们可以在 Click 事件处理程序中更新这个属性来改变按钮的状态。



private void ThreeStateButton_Click(object sender, RoutedEventArgs e)
{
    ThreeStateButton button = sender as ThreeStateButton;
    if(button.State == 0)
    {
        button.State = 1;
    }
    else if(button.State == 1)
    {
        button.State = 2;
    }
    else
    {
        button.State = 0;
    }
}

这是一个大概的思路,实际实现中可能还需要根据具体需求进行调整。