A read-only CheckBox in C# WPF A read-only CheckBox in C# WPF wpf wpf

A read-only CheckBox in C# WPF


What about data binding to the IsHitTestVisible property?

For example, assuming an MVVM approach:

  1. Add a IsReadOnly property to your view model, initially set as true to allow click.
  2. Binding this property to CheckBox.IsHitTestVisible.
  3. After the first click, update your view model to set this value to false, preventing any further clicks.

I don't have this exact requirement, I just needed an always read only checkbox, and it seems to solve the problem nicely. Also note Goran's comment below about the Focusable property.


This answer is not your question, but it answers the question from the title.

Checkbox in WPF does not have the IsReadOnly property.But, similar behavior is achieved using propertiesIsHitTestVisible="False" and Focusable="False"

      <CheckBox IsHitTestVisible="False"                Focusable="False"/>


I don't think that creating a whole control for this is necessary.The issue that you're running into comes from the fact that the place where you see 'the check' isn't really the checkbox, it's a bullet. If we look at the ControlTemplate for a CheckBox we can see how that happens (Though I like the Blend template better). As a part of that, even though your binding on the IsChecked property is set to OneWay it is still being updated in the UI, even if it is not setting the binding value.

As such, a really simple way to fix this, is to just modify the ControlTemplate for the checkbox in question.

If we use Blend to grab the control template we can see the Bullet inside the ControlTemplate that represents the actual checkbox area.

        <BulletDecorator SnapsToDevicePixels="true"                         Background="Transparent">            <BulletDecorator.Bullet>                <Microsoft_Windows_Themes:BulletChrome Background="{TemplateBinding Background}"                                                       BorderBrush="{TemplateBinding BorderBrush}"                                                       IsChecked="{TemplateBinding IsChecked}"                                                       RenderMouseOver="{TemplateBinding IsMouseOver}"                                                       RenderPressed="{TemplateBinding IsPressed}" />            </BulletDecorator.Bullet>            <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"                              Margin="{TemplateBinding Padding}"                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"                              RecognizesAccessKey="True" />        </BulletDecorator>

In here, the IsChecked and RenderPressed are what are actually making the 'Check' appear, so to fix it, we can remove the binding from the IsChecked property on the ComboBox and use it to replace the TemplateBinding on the IsChecked property of the Bullet.

Here's a small sample demonstrating the desired effect, do note that to maintain the Vista CheckBox look the PresentationFramework.Aero dll needs to be added to the project.

<Window x:Class="Sample.Window1"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"    Title="Window1"    Height="300"    Width="300"><Window.Resources>    <SolidColorBrush x:Key="CheckBoxFillNormal"                     Color="#F4F4F4" />    <SolidColorBrush x:Key="CheckBoxStroke"                     Color="#8E8F8F" />    <Style x:Key="EmptyCheckBoxFocusVisual">        <Setter Property="Control.Template">            <Setter.Value>                <ControlTemplate>                    <Rectangle SnapsToDevicePixels="true"                               Margin="1"                               Stroke="Black"                               StrokeDashArray="1 2"                               StrokeThickness="1" />                </ControlTemplate>            </Setter.Value>        </Setter>    </Style>    <Style x:Key="CheckRadioFocusVisual">        <Setter Property="Control.Template">            <Setter.Value>                <ControlTemplate>                    <Rectangle SnapsToDevicePixels="true"                               Margin="14,0,0,0"                               Stroke="Black"                               StrokeDashArray="1 2"                               StrokeThickness="1" />                </ControlTemplate>            </Setter.Value>        </Setter>    </Style>    <Style x:Key="CheckBoxStyle1"           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 SnapsToDevicePixels="true"                                     Background="Transparent">                        <BulletDecorator.Bullet>                            <Microsoft_Windows_Themes:BulletChrome Background="{TemplateBinding Background}"                                                                   BorderBrush="{TemplateBinding BorderBrush}"                                                                   RenderMouseOver="{TemplateBinding IsMouseOver}" />                        </BulletDecorator.Bullet>                        <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"                                          Margin="{TemplateBinding Padding}"                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"                                          RecognizesAccessKey="True" />                    </BulletDecorator>                    <ControlTemplate.Triggers>                        <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><Grid>    <StackPanel>        <CheckBox x:Name="uiComboBox"                  Content="Does not set the backing property, but responds to it.">            <CheckBox.Style>                <Style TargetType="{x:Type CheckBox}">                    <Setter Property="Template">                        <Setter.Value>                            <ControlTemplate TargetType="{x:Type CheckBox}">                                <BulletDecorator SnapsToDevicePixels="true"                                                 Background="Transparent">                                    <BulletDecorator.Bullet>                                        <Microsoft_Windows_Themes:BulletChrome Background="{TemplateBinding Background}"                                                                               BorderBrush="{TemplateBinding BorderBrush}"                                                                               RenderMouseOver="{TemplateBinding IsMouseOver}"                                                                               IsChecked="{Binding MyBoolean}">                                        </Microsoft_Windows_Themes:BulletChrome>                                    </BulletDecorator.Bullet>                                    <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"                                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"                                                      Margin="{TemplateBinding Padding}"                                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"                                                      RecognizesAccessKey="True" />                                </BulletDecorator>                                <ControlTemplate.Triggers>                                    <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>            </CheckBox.Style>        </CheckBox>        <TextBlock Text="{Binding MyBoolean, StringFormat=Backing property:{0}}" />        <CheckBox IsChecked="{Binding MyBoolean}"                  Content="Sets the backing property." />    </StackPanel></Grid></Window>

And the code behind, with our backing Boolean value:

public partial class Window1 : Window, INotifyPropertyChanged{    public Window1()    {        InitializeComponent();        this.DataContext = this;    }    private bool myBoolean;    public bool MyBoolean    {        get        {            return this.myBoolean;        }        set        {            this.myBoolean = value;            this.NotifyPropertyChanged("MyBoolean");        }    }    #region INotifyPropertyChanged Members    public event PropertyChangedEventHandler PropertyChanged;    private void NotifyPropertyChanged(String info)    {        if (PropertyChanged != null)        {            PropertyChanged(this, new PropertyChangedEventArgs(info));        }    }    #endregion}