添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
刚毅的香蕉  ·  OpenSSL 1.1.1-pre1 ...·  1 年前    · 
严肃的面包  ·  Win10 ...·  1 年前    · 

UI 设计中经常会用到 Toggle Button,用于切换不同的状态。
UWP 中有 ToggleSwitch , 长这样:
在这里插入图片描述

WPF 中有 ToggleButton , 长这样:
在这里插入图片描述
嗯?????(黑人问号脸)

=========== 分割线 ===========

WPF 中需要给 ToggleButton 自定义控件模板,以实现 ToggleSwitch 的效果,先上效果图:
在这里插入图片描述

Style:

<ControlTemplate.Resources>
	<Storyboard x:Key="OnChecked">
		<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)"
										  Storyboard.TargetName="path">
			<EasingThicknessKeyFrame KeyTime="0" Value="40,0,0,0"/>
		</ThicknessAnimationUsingKeyFrames>
	</Storyboard>
	<Storyboard x:Key="OnUnchecked">
		<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)"
										  Storyboard.TargetName="path">
			<EasingThicknessKeyFrame KeyTime="0" Value="0"/>
		</ThicknessAnimationUsingKeyFrames>
	</Storyboard>
</ControlTemplate.Resources>
<Border x:Name="toggleBorder"
		CornerRadius="13"
		Background="Green"
		Width="60"
		Height="26"
		BorderThickness="1"
		BorderBrush="Black">
		<Path x:Name="path">
			<Path.Fill>
				<LinearGradientBrush StartPoint="1,0" EndPoint="1,1">
					<GradientStop Color="White"/>
				</LinearGradientBrush>
			</Path.Fill>
			<Path.Data>
				<GeometryGroup>
					<GeometryGroup.Children>
						<EllipseGeometry Center="6,12" RadiusX="9" RadiusY="9"/>
					</GeometryGroup.Children>
				</GeometryGroup>
			</Path.Data>
		</Path>
	</Grid>
</Border>

加上 Trigger:

<ControlTemplate.Triggers>
	<EventTrigger RoutedEvent="ToggleButton.Checked">
		<BeginStoryboard Storyboard="{StaticResource OnChecked}"/>
	</EventTrigger>
	<EventTrigger RoutedEvent="ToggleButton.Unchecked">
		<BeginStoryboard Storyboard="{StaticResource OnUnchecked}"/>
	</EventTrigger>
	<Trigger Property="IsChecked" Value="True">
		<Setter Property="Background" Value="DimGray"/>
		<Setter TargetName="toggleBorder" Property="Background" Value="Green"/>
		<Setter TargetName="toggleBorder" Property="BorderBrush" Value="Green"/>
	</Trigger>
	<Trigger Property="IsChecked" Value="False">
		<Setter TargetName="toggleBorder" Property="Background" Value="LightGray"/>
		<Setter TargetName="path" Property="Fill">
			<Setter.Value>
				<LinearGradientBrush StartPoint="1,0" EndPoint="1,1">
					<GradientStop Color="Gray"/>
				</LinearGradientBrush>
			</Setter.Value>
		</Setter>
		<Setter TargetName="path" Property="Data">
			<Setter.Value>
				<GeometryGroup>
					<GeometryGroup.Children>
						<EllipseGeometry Center="13,12" RadiusX="9" RadiusY="9"/>
					</GeometryGroup.Children>
				</GeometryGroup>
			</Setter.Value>
		</Setter>
	</Trigger>
</ControlTemplate.Triggers>

到这儿自定义 ToggleButton 就基本完成了,下面是扩展部分。

=============================

扩展一:High Contrast

实际开发中,往往需要控件支持高对比度(High Contrast):

using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
namespace ToggleButtonStyle
    public class HighContrastHelper : DependencyObject
        private HighContrastHelper()
            SystemParameters.StaticPropertyChanged += SystemParameters_StaticPropertyChanged;
        ~HighContrastHelper()
            SystemParameters.StaticPropertyChanged -= SystemParameters_StaticPropertyChanged;
        private static HighContrastHelper instance;
        public static HighContrastHelper Instance
                if (instance == null)
                    instance = new HighContrastHelper();
                return instance;
        public void ApplyCurrentTheme()
            if (SystemParameters.HighContrast)
                SolidColorBrush windowbrush = SystemColors.WindowBrush;
                if (windowbrush.Color.R == 255 && windowbrush.Color.G == 255 && windowbrush.Color.B == 255)
                    Instance.IsHighContrastWhite = true;
                    Instance.IsHighContrastBlack = false;
                else if (windowbrush.Color.R == 0 && windowbrush.Color.G == 0 && windowbrush.Color.B == 0)
                    Instance.IsHighContrastWhite = false;
                    Instance.IsHighContrastBlack = true;
                    Instance.IsHighContrastWhite = false;
                    Instance.IsHighContrastBlack = false;
        void SystemParameters_StaticPropertyChanged(object sender, PropertyChangedEventArgs e)
            if (e.PropertyName == "HighContrast")
                ApplyCurrentTheme();
        public static readonly DependencyProperty IsHighContrastWhiteProperty = DependencyProperty.Register(
            "IsHighContrastWhite",
            typeof(bool),
            typeof(HighContrastHelper),
            new PropertyMetadata(false));
        public static readonly DependencyProperty IsHighContrastBlackProperty = DependencyProperty.Register(
            "IsHighContrastBlack",
            typeof(bool),
            typeof(HighContrastHelper),
            new PropertyMetadata(false));
        public bool IsHighContrastWhite
            get { return (bool)GetValue(IsHighContrastWhiteProperty); }
            private set { SetValue(IsHighContrastWhiteProperty, value); }
        public bool IsHighContrastBlack
            get { return (bool)GetValue(IsHighContrastBlackProperty); }
            private set { SetValue(IsHighContrastBlackProperty, value); }

注:系统事件在析构函数中最好取消订阅,以减小内存开销。

然后增加相应的 Trigger:

<MultiDataTrigger>
	<MultiDataTrigger.Conditions>
		<Condition Binding="{Binding Path=IsHighContrastWhite, Source={x:Static local:HighContrastHelper.Instance}}" Value="true" />
		<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" Value="true"/>
		<Condition Binding="{Binding ElementName=toggleButton, Path=IsChecked}" Value="true"/>
	</MultiDataTrigger.Conditions>
	<Setter TargetName="toggleBorder" Property="Background" Value="Blue"/>
</MultiDataTrigger>
<MultiDataTrigger>
	<MultiDataTrigger.Conditions>
		<Condition Binding="{Binding Path=IsHighContrastWhite, Source={x:Static local:HighContrastHelper.Instance}}" Value="true" />
		<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" Value="true"/>
		<Condition Binding="{Binding ElementName=toggleButton, Path=IsChecked}" Value="false"/>
	</MultiDataTrigger.Conditions>
	<Setter TargetName="toggleBorder" Property="Background" Value="Black"/>
</MultiDataTrigger>
<MultiDataTrigger>
	<MultiDataTrigger.Conditions>
		<Condition Binding="{Binding Path=IsHighContrastBlack, Source={x:Static local:HighContrastHelper.Instance}}" Value="true" />
		<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" Value="true"/>
		<Condition Binding="{Binding ElementName=toggleButton, Path=IsChecked}" Value="true"/>
	</MultiDataTrigger.Conditions>
	<Setter TargetName="toggleBorder" Property="Background" Value="Aqua"/>
</MultiDataTrigger>
<MultiDataTrigger>
	<MultiDataTrigger.Conditions>
		<Condition Binding="{Binding Path=IsHighContrastBlack, Source={x:Static local:HighContrastHelper.Instance}}" Value="true" />
		<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" Value="true"/>
		<Condition Binding="{Binding ElementName=toggleButton, Path=IsChecked}" Value="false"/>
	</MultiDataTrigger.Conditions>
	<Setter TargetName="toggleBorder" Property="Background" Value="Yellow"/>
</MultiDataTrigger>

要控件支持高对比度,还需给控件设置 Tag 属性:

<Setter Property="Tag" Value="{DynamicResource {x:Static SystemParameters.HighContrastKey}}"/>

High Contrast White On:
在这里插入图片描述

High Contrast White Off:在这里插入图片描述
High Contrast Black On:
在这里插入图片描述

High Contrast Black Off:
在这里插入图片描述
扩展二:Accessibility

开发中往往还需要支持 Narrator 读取文本:

TabIndex="1"
AutomationProperties.Name="CustomizedToggle"

自动化测试 AutomationID:

AutomationProperties.AutomationId="CustomizedToggle"

需要注意的一点是当打开 Narrator,使用键盘的 Enter/Space 键切换 ToggleButton 的时候,其 Click 事件往往不能触发,这时候需要使用其 Checked/UnChecked 事件。

最后附上源码:WPF Toggle Button Style

That’s All, thx~

PS:原创不易,转载请注明出处。

UI 设计中经常会用到 Toggle Button,用于切换不同的状态。UWP 中有 ToggleSwitch, 长这样:WPF 中有 ToggleButton, 长这样:嗯?????(黑人问号脸)=========== 分割线 ===========WPF 中需要给 ToggleButton 自定义控件模板,以实现 ToggleSwitch 的效果,先上效果图:Style:&lt;ControlTemplate.Resources&gt; &lt;Storyboard x:Key="OnC <LinearGradientBrush x:Key="ButtonNormalBackgroundFill" EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FFFFFFFF" Offset="... 源码下载地址https://download.csdn.net/download/shizu11zz/24417299https://download.csdn.net/download/shizu11zz/24417299 直接贴源码,有帮助的话求点个赞,不过分吧: 【MainWindow.Xaml】 <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
要实现在Button里面加入图标或者图形以及文字,我们就需要在Button里面用一个WrapPanel控件,这个WrapPanel控件会把我们的图标或者文字进行包裹,并显示出来。 Xaml: <Button HorizontalAlignment="Left" Margin="222,151,0,0" VerticalAlignment="Top" Widt...
Xaml代码: <Window x:Class="WPF0315b.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
在上一章讲了单选框样式,单选扩展依赖属性类继承于RadioButton。然后在自定义样式,RadioButton中需要把GroupName设置为同一组名称即可。 复选框实现原理同单选框相同,主要区别在于实现多选需要继承ToggleButton类,此类每个按钮是可以单独选择的。 先看一下实现效果: 增加几项依赖属性和单选框一样。这里就不再多介绍。 /// <summary> /// 多选框 /// </summary> public class N
WPF自定义开关切换按钮 突发奇想先要自己写一个开关按钮,说干就开干了,以下为View视图布局代码,开关按钮的样式就直接在这里定义了,主要呢通过定义触发器来完成按钮的切换。 ```csharp <Window x:Class="DEMO.View.StatusWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsof
导入PSD模板完成后,应如图所示。应该只有OFF_Copy这一个画布(Canvas) 然后我们做如图中黄色的那部分操作,把这个画布(Canvas)转成一个UserControl,点击后会弹出一个让你起名字的对话框,输入自定义的名称后会在工程中生成一个UserControl控件。如图所示: 接下来,我们需要做一个控件的模板(Temp
WPF自定义MessageBox是一种在WPF应用程序中创建自定义消息框的方法。传统上,MessageBox是弹出对话框形式的标准Windows消息框,但开发人员可以自定义WPF消息框,以适应应用程序的外观和感觉。 自定义WPF MessageBox需要将对话框视为窗口,并在该窗口中添加自定义UI元素。实现此目标的一种方法是使用WPF的模板技术。通过在模板中定义对话框元素,开发人员可以定义自己的消息框UI。 为了使自定义MessageBox更具灵活性,开发人员还可以考虑使用自己的消息框类,该类包含特定于应用程序的消息框属性和方法。例如,开发人员可以定义自己的标题、文本、按钮和事件处理程序,以便更好地控制该消息框的外观和行为。 总的来说,WPF自定义MessageBox提供了一种强大的用于在WPF应用程序中创建更具个性化消息框的方法。通过使用WPF的模板和自定义类技术,开发人员可以完全定制消息框的外观和行为,以满足应用程序的特定需求。