Search code examples
wpfxamldatatrigger

Unchecking a CheckBox from a Style Setter?


I have multiple datatriggers of the form:

 <Style x:Key="VerifyCheckBox" TargetType="{x:Type CheckBox}">
            <Setter Property="Height" Value="14" />
            <Setter Property="FontSize" Value="12" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=PrimaryInsuranceCompany, Path=(Validation.HasError)}" Value="True">
                    <Setter Property="IsEnabled" Value="False" />
                    <Setter Property="IsChecked" Value="False" />
                </DataTrigger>

The IsEnabled property on the CheckBox is set correctly. However, the IsChecked property does not get unchecked if it had been manually checked in the first place.

Can IsChecked be unchecked from a Setter?

Edit#1

To complicate matters a bit more, the checkbox is bound to a property in my viewmodel as:

  <CheckBox 
                  Style="{StaticResource VerifyCheckBox}"
                  IsChecked="{Binding PrimaryInsurance.SelectedInsurance.Verify}" 
                  Content="Verify" HorizontalAlignment="Left" Margin="789,92,0,676" Width="46" />

And there are multiple DataTrigger s in the Style.Triggers each checking a different element on the UI. In short, the UI has all the data validation. For instance, the element named above, PrimaryInsuranceCompany is:

 <wc:AutoFilteredComboBox 
                  Name="PrimaryInsuranceCompany"
                  IsEnabled="{Binding PrimaryInsurance.Enabled}"
                  ItemsSource="{Binding PrimaryInsurance.AllCompanies}"
                  ItemTemplate="{StaticResource CompanyTemplate}"
                  IsEditable="True"
                  IsCaseSensitive="False" 
                  IsTextSearchEnabled="True" 
                  TextSearch.TextPath="Companyname"
                  Text="{Binding PrimaryInsurance.NewCompanyName, UpdateSourceTrigger=PropertyChanged}"
                  theFilter="{Binding PrimaryInsurance.TheFilter}" 
                  SelectedItem="{Binding PrimaryInsurance.SelectedInsurance.Company}"
                  h:ComboBoxRegexValidator.RegexText="{x:Static h:RegexLibrary.NonEmptyRegex}"
                  HorizontalAlignment="Left" Margin="590,138,0,0" VerticalAlignment="Top" Width="363"  />

So with the combobox element in particular, I was trying to avoid duplicating the validation process in the view model since it is already being done directly in the view. Can this be done?


Solution

  • This quite often causes a confusion. You might want to read this: https://msdn.microsoft.com/en-us/library/vstudio/ms743230%28v=vs.100%29.aspx. Basically, dependency properties in wpf might be set in different places: locally (IsChecked=True), in style, in trigger, and so on. When property is set in multiple places, specific resolution order is used to resolve the conflict. Here is an example:

    <Window.Resources>
        <Style x:Key="VerifyCheckBox" TargetType="{x:Type CheckBox}">
            <Setter Property="Height" Value="14" />
            <Setter Property="FontSize" Value="12" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding TestValue}" Value="True">
                    <Setter Property="IsChecked" Value="False" />
                    <Setter Property="IsEnabled" Value="False" />                    
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <CheckBox Content="Hey there" IsChecked="True" Style="{StaticResource VerifyCheckBox}" />
    

    Here we set IsChecked in two places: locally (IsChecked=True) and in trigger. Local value has higher priority and because of that, when TestValue will become true checkbox will not be unchecked. However we did not set IsEnabled locally, so it will have it's value from trigger. Note that if we did set IsEnabled=True locally, trigger would have no effect at all.

    Now let's try like this:

    <Window.Resources>
        <Style x:Key="VerifyCheckBox" TargetType="{x:Type CheckBox}">
            <Setter Property="Height" Value="14" />
            <Setter Property="FontSize" Value="12" />
            <Setter Property="IsChecked" Value="True"></Setter>
            <Style.Triggers>
                <DataTrigger Binding="{Binding TestValue}" Value="True">
                    <Setter Property="IsChecked" Value="False" />
                    <Setter Property="IsEnabled" Value="False" />                    
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <CheckBox Content="Hey there" Style="{StaticResource VerifyCheckBox}" />
    

    We moved IsChecked initial setter in style and now it works as expected, because trigger has priority over values in style setter.

    Update: user clicking does not change behavior above. So, if you have local IsChecked=True, then user clicked twice, then TestValue becomes true - it will not be unchecked. And if you do the same but initialize IsChecked=True in style setter - it will be unchecked.