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;
}
}
这是一个大概的思路,实际实现中可能还需要根据具体需求进行调整。