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

时间:2017-02-07 11:48:52

标签: c# wpf

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

Style="{StaticResource {x:Type ToggleButton}}"

这给了我喜欢的风格,但我注意到了一种恼人的副作用。我需要能够在禁用控件的同时更改所选按钮。这与正常的单选按钮一样正常工作。但是,使用切换按钮样式按钮,它不再显示其中一个按钮被选中。

在以下演示中,如果您反复点击“启用切换”功能,请执行以下操作。按钮,您可以看到重新启用时所选按钮仍然突出显示。但是,如果您更改所选按钮并将其重新启用,然后重新启用(点击'切换启用','更改值','切换启用' ;),两个按钮都没有突出显示。

我想要实现的目标:

  1. 尽可能接近ToggleButton的风格。
  2. 禁用选中的按钮时,请保持蓝色背景但不透明。
  3. 无论值是否已更改,重新启用按钮时都具有标准的ToggleButton样式。
  4. 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>
    

    代码背后:

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

2 个答案:

答案 0 :(得分:2)

这是禁用ToggleButton的样子。如果要更改其外观,则应定义自定义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>

enter image description here

答案 1 :(得分:1)

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

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>

您还可以为RadioButton定义样式,并将其基于ToggleButton,因此不必为每个RadioButton指定样式。

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