将 WPF 单选按钮样式为具有正确 IsEnabled 行为的切换按钮

scl*_*e81 5 c# wpf

我需要将一些分组的单选按钮设置为切换按钮。为此,我对单选按钮应用了以下样式:

Style="{StaticResource {x:Type ToggleButton}}"
Run Code Online (Sandbox Code Playgroud)

这给了我想要的风格,但我注意到一个恼人的副作用。我需要能够在禁用控件的同时更改所选按钮。这对普通单选按钮按预期工作。但是,对于切换按钮样式的按钮,它不再将其中一个按钮显示为被选中。

在下面的演示中,如果您反复单击“启用切换”按钮,您可以看到所选按钮在重新启用时仍然突出显示。但是,如果您在禁用时更改所选按钮,然后重新启用(单击“启用切换”、“更改值”、“启用切换”),则两个按钮都不会突出显示。

我正在努力实现的目标:

  1. 尽可能接近 ToggleButton 的样式。
  2. 当一个选中的按钮被禁用时,保持蓝色背景但不透明。
  3. 无论值是否已更改,重新启用按钮时都具有标准的 ToggleButton 样式。

XAML:

<Window x:Class="ToggleButtonDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ToggleButtonDemo"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="200"
        Name="demoWindow"
        DataContext="{Binding ElementName=demoWindow}">
    <StackPanel>
        <GroupBox Header="Radio" IsEnabled="{Binding Enable}">
            <StackPanel Orientation="Horizontal">
                <RadioButton Name="radio1" Content="One" GroupName="RadioGroup" IsChecked="True"/>
                <RadioButton Name="radio2" Content="Two" GroupName="RadioGroup"/>
            </StackPanel>
        </GroupBox>
        <GroupBox Header="Toggle" IsEnabled="{Binding Enable}">
            <StackPanel Orientation="Horizontal">
                <RadioButton Name="toggle1" Content="One" GroupName="ToggleGroup" Style="{StaticResource {x:Type ToggleButton}}" IsChecked="True"/>
                <RadioButton Name="toggle2" Content="Two" GroupName="ToggleGroup" Style="{StaticResource {x:Type ToggleButton}}"/>
            </StackPanel>
        </GroupBox>
        <Button Name="toggle" Content="Toggle enabled" Click="toggle_Click"/>
        <Button Name="changeValue" Content="Change value" Click="changeValue_Click"/>
    </StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)

后面的代码:

using System.ComponentModel;
using System.Windows;

namespace ToggleButtonDemo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {

        private bool mEnable = true;

        public bool Enable
        {
            get
            {
                return mEnable;
            }
            set
            {
                mEnable = value;
                OnPropertyChanged(nameof(Enable));
            }
        }

        public MainWindow()
        {
            InitializeComponent();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private void toggle_Click(object sender, RoutedEventArgs e)
        {
            Enable = !Enable;
        }

        private void changeValue_Click(object sender, RoutedEventArgs e)
        {
            if (radio1.IsChecked == true)
            {
                radio2.IsChecked = true;
            }
            else if (radio2.IsChecked == true)
            {
                radio1.IsChecked = true;
            }

            if (toggle1.IsChecked == true)
            {
                toggle2.IsChecked = true;
            }
            else if (toggle2.IsChecked == true)
            {
                toggle1.IsChecked = true;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*nks 11

我从下面引用的链接中得到了这个答案......我以前从未见过这样做过,但与从 Blend 中获取完整样式定义相比,它使用更少的 XAML 效果很好(除非您需要自定义样式):

https://social.msdn.microsoft.com/Forums/vstudio/en-US/e0ce86f0-8fa3-4aa9-9617-4157326ee077/make-radiobutton-appear-as-togglebutton?forum=wpf

<RadioButton Style="{StaticResource {x:Type ToggleButton}}">Yes</RadioButton>

<RadioButton Style="{StaticResource {x:Type ToggleButton}}">no</RadioButton>
Run Code Online (Sandbox Code Playgroud)

您还可以为 RadioButton 定义 Style 并将其基于 ToggleButton,这样您就不必为每个 RadioButton 指定 Style。

<Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="RadioButton"/>
Run Code Online (Sandbox Code Playgroud)


mm8*_*mm8 5

这就是残疾人的ToggleButton样子。如果你想改变它的外观,你应该定义 custom ControlTemplate。请参考以下示例:

<Window x:Class="ToggleButtonDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ToggleButtonDemo"
    mc:Ignorable="d"
    Title="MainWindow" Height="200" Width="200"
    Name="demoWindow"
    DataContext="{Binding ElementName=demoWindow}">
<Window.Resources>
    <Style x:Key="FocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
    <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
    <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
    <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
    <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
    <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
    <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
    <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
    <SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
    <Style TargetType="{x:Type ToggleButton}">
        <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
        <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
        <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                        <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Button.IsDefaulted" Value="true">
                            <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
                            <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Pressed.Background}"/>
                            <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Pressed.Border}"/>
                        </Trigger>
                        <Trigger Property="IsChecked" Value="True">
                            <Setter Property="Background" TargetName="border" Value="#FFBCDDEE"/>
                            <Setter Property="BorderBrush" TargetName="border" Value="#FF245A83"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Opacity" TargetName="border" Value="0.7"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<StackPanel>
    <GroupBox Header="Radio" IsEnabled="{Binding Enable}">
        <StackPanel Orientation="Horizontal">
            <RadioButton Name="radio1" Content="One" GroupName="RadioGroup" IsChecked="True"/>
            <RadioButton Name="radio2" Content="Two" GroupName="RadioGroup"/>
        </StackPanel>
    </GroupBox>
    <GroupBox Header="Toggle" IsEnabled="{Binding Enable}">
        <StackPanel Orientation="Horizontal">
            <RadioButton Name="toggle1" Content="One" GroupName="ToggleGroup" Style="{StaticResource {x:Type ToggleButton}}" IsChecked="True"/>
            <RadioButton Name="toggle2" Content="Two" GroupName="ToggleGroup" Style="{StaticResource {x:Type ToggleButton}}"/>
        </StackPanel>
    </GroupBox>
    <Button Name="toggle" Content="Toggle enabled" Click="toggle_Click"/>
    <Button Name="changeValue" Content="Change value" Click="changeValue_Click"/>
</StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明