Styling the indeterminate state of a WPF checkbox

2019-03-12 18:05发布

I want to style the indeterminate state of a WPF checkbox. We have a treeview control with checkboxes, and we want the indeterminate state to represent that some descendants are checked and some are unchecked.

The solution I'm seeing everywhere is to override the default control template for a checkbox and do what I need to do.

I have two problems with that:

  1. I can't find the control template for a normal Aero checkbox. This one: http://msdn.microsoft.com/en-us/library/ms752319.aspx looks goofy.

  2. The control template I get from Expression Blend has that BulletChrome element in it, and I can't figure out what to do with that.

So does anyone know where to get a checkbox control template that looks "normal" or is there an easier way to just style the indeterminate state by itself?

I'm sure there's an easy way I'm just overlooking... Right?

9条回答
闹够了就滚
2楼-- · 2019-03-12 18:29

You can set the checkbox's IsThreeState property to true.

This, however, allows toggling the checkbox's value to null.
If that is undesired, you can instead add to your CheckBox's Template a trigger for the null value, just like Greg Bacchus shows in his answer:

<ControlTemplate.Triggers>
    <Trigger Property="IsChecked" Value="{x:Null}">
        <!-- TODO: Do Stuff Here -->
    </Trigger>
</ControlTemplate.Triggers>
查看更多
狗以群分
3楼-- · 2019-03-12 18:33

Try this (modified from the article that publicgk linked to)

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" Title="MainWindow" Height="350" Width="525">
  <Window.Resources>
    <Style x:Key="CheckRadioFocusVisual">
      <Setter Property="Control.Template">
        <Setter.Value>
          <ControlTemplate>
            <Rectangle Margin="14,0,0,0"
                       StrokeThickness="1"
                       Stroke="Black"
                       StrokeDashArray="1 2"
                       SnapsToDevicePixels="true"/>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    <Style x:Key="EmptyCheckBoxFocusVisual">
      <Setter Property="Control.Template">
        <Setter.Value>
          <ControlTemplate>
            <Rectangle Margin="1"
                       StrokeThickness="1"
                       Stroke="Black"
                       StrokeDashArray="1 2"
                       SnapsToDevicePixels="true"/>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    <SolidColorBrush x:Key="CheckBoxFillNormal"
                     Color="#F4F4F4"/>
    <SolidColorBrush x:Key="CheckBoxStroke"
                     Color="#8E8F8F"/>
    <Style x:Key="{x:Type CheckBox}"
         TargetType="{x:Type CheckBox}">
      <Setter Property="Foreground"
            Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
      <Setter Property="Background"
            Value="{StaticResource CheckBoxFillNormal}"/>
      <Setter Property="BorderBrush"
            Value="{StaticResource CheckBoxStroke}"/>
      <Setter Property="BorderThickness"
            Value="1"/>
      <Setter Property="FocusVisualStyle"
            Value="{StaticResource EmptyCheckBoxFocusVisual}"/>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type CheckBox}">
            <BulletDecorator Background="Transparent" 
                             SnapsToDevicePixels="true">
              <BulletDecorator.Bullet>
                <theme:BulletChrome Background="{TemplateBinding Background}"
                                    BorderBrush="{TemplateBinding BorderBrush}"
                                    RenderMouseOver="{TemplateBinding IsMouseOver}"
                                    RenderPressed="{TemplateBinding IsPressed}"
                                    IsChecked="{TemplateBinding IsChecked}"/>
              </BulletDecorator.Bullet>
              <ContentPresenter Margin="{TemplateBinding Padding}"
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                RecognizesAccessKey="True"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
            </BulletDecorator>
            <ControlTemplate.Triggers>
              <Trigger Property="IsChecked" 
                       Value="{x:Null}">
                <!-- TODO: Do Stuff Here -->
              </Trigger>
              <Trigger Property="HasContent"
                       Value="true">
                <Setter Property="FocusVisualStyle"
                        Value="{StaticResource CheckRadioFocusVisual}"/>
                <Setter Property="Padding"
                        Value="4,0,0,0"/>
              </Trigger>
              <Trigger Property="IsEnabled"
                       Value="false">
                <Setter Property="Foreground"
                        Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Resources>
  <StackPanel>
    <CheckBox IsChecked="True" Content="Checked"/>
    <CheckBox IsChecked="{x:Null}" Content="Unknown"/>
    <CheckBox IsChecked="False" Content="Not Checked"/>
  </StackPanel>
</Window>
查看更多
贪生不怕死
4楼-- · 2019-03-12 18:34

Have you already tried to download the Aero Theme xaml and looked into it?
Where can I download Microsoft's standard WPF themes from?

查看更多
贼婆χ
5楼-- · 2019-03-12 18:36

Have you thought about using SimpleStyles as the base for control?

ExpressionSimpleStyles

By selecting this control from the Assets panel, Expression Blend will place a new resource dictonary in your project that you can use to modify the style as you please. Might be a better starting point than trying to hack into the Chrome for the standard checkbox.

查看更多
SAY GOODBYE
6楼-- · 2019-03-12 18:38

Another option may be to style a toggle button as it has multiple states as well. In past projects I have created custom toggle buttons with multiple states that look and function as chekcboxes. I did use blend to make the changes but in using a tggle button as the base I was able to create a more customized look and feel for the various states of the button/chekcbox. Using a toggle button can bypass a lot of the chrome related issues that are tightly boud to a standard chekcbox control.

查看更多
我欲成王,谁敢阻挡
7楼-- · 2019-03-12 18:48

Using the template from Blend:

To make BulletChrome work, you need to add a reference to PresentationFramework.Aero, and add the xml namespace declaration for the "theme" namespace:

xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"

I didn't try this myself but I believe it should work (I've done it with Luna).

查看更多
登录 后发表回答