3

I'm thinking out different ways to have a WPF ComboBox show blank as if nothing is selected when IsEnabled is set to false. Like always I'm trying to do this without having to redefine the whole control template for the ComboBox which is always a struggle I have with WPF. If anybody has any solutions more elegant than redefining the whole ComboBox control template please let me know.

The reason for what I'm trying to do is I have a CheckBox that represents an "All" option and when checked it disables the ComboBox which is used to pick only a single individual item. If my CheckBox is checked it is sometimes confusing to the users to see a value remaining in the ComboBox since that value has no meaning in that state of the UI.

Another requirement is that the solution cannot modify the SelectedValue, SelectedIndex, or SelectedItem values of the ComboBox since I would like to retain the previuosly selected item in the case that the users unchecks the "All" CheckBox.

Solution based on HCL's answer:

<ComboBox IsEnabled="{Binding ElementName=myCheckBox, Path=IsChecked}"
          ItemsSource="{Binding Path=MyItems}"
          SelectedValue="{Binding Path=MySelectedItem}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <ContentControl x:Name="content" Content="{Binding MyItemDescription}" />
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ComboBox}, Path=IsEnabled}"
                             Value="False">
                    <Setter TargetName="content"
                            Property="Visibility"
                            Value="Hidden" />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>
Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
jpierson
  • 16,435
  • 14
  • 105
  • 149

3 Answers3

2

You can do something with triggers:

Try setting the ItemTemplate to an empty DataTemplate when the box is disabled. This will affect the rendering of the selected item and therefore hide it.

Another simple but not very nice solution would be to set the foreground color to the same as a background color.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
HCL
  • 36,053
  • 27
  • 163
  • 213
0

I believe you can do this with a Style, rather than redefining the control template. Use a Trigger on the IsEnabled property to set the text shown in the ComboBox. Altering the SelectedItem would be my first approach, but since you don't want to do that, you may find success setting the DisplayMemberPath. Something like this (untested)...

<Style TargetType="{x:Type ComboBox}">
    <Style.Triggers>
        <Trigger Property="IsEnabled" Value="False">
            <Trigger.Setters>
                <Setter Property="DisplayMemberPath" Value="{x:Null}"/>
            </Trigger.Setters>
        </Trigger>
    </Style.Triggers>
</Style>
Dan J
  • 16,319
  • 7
  • 50
  • 82
  • Unfortunately this did not work in my tests although it's possible that I have something wrong. I did like the simplicity more than specifying an ItemTemplate. – jpierson Jan 19 '11 at 21:55
  • In trying to figure out whether this method is actually possible I came across this post on the MSDN forums which seems pretty interesting. http://social.msdn.microsoft.com/Forums/en/wpf/thread/4c359378-ba98-42a1-a468-0f18f5626fcc – jpierson Jan 20 '11 at 00:57
0

Here's a style that does what you want. It employs a technique that I use all the time: a grid that contains multiple versions of the control, and data triggers that ensure that only one version is visible at any one time.

    <ComboBox.Style>
      <Style TargetType="ComboBox">
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="ComboBox">
              <DockPanel>
                <CheckBox x:Name="IsActive" DockPanel.Dock="Left"/>
                <Grid>
                  <ComboBox
                    ItemsSource="{TemplateBinding ItemsSource}"
                    SelectedItem="{TemplateBinding SelectedItem}"
                    SelectedIndex="{TemplateBinding SelectedIndex}"
                    SelectedValue="{TemplateBinding SelectedValue}">
                    <ComboBox.Style>
                      <Style TargetType="ComboBox">
                        <Setter Property="Visibility" Value="Visible"/>
                        <Style.Triggers>
                          <DataTrigger Binding="{Binding ElementName=IsActive, Path=IsChecked}" Value="False">
                            <Setter Property="Visibility" Value="Collapsed"/>
                          </DataTrigger>
                        </Style.Triggers>
                      </Style>
                    </ComboBox.Style>
                  </ComboBox>
                  <ComboBox>
                    <ComboBox.Style>
                      <Style TargetType="ComboBox">
                        <Setter Property="Visibility" Value="Collapsed"/>
                        <Style.Triggers>
                          <DataTrigger Binding="{Binding ElementName=IsActive, Path=IsChecked}" Value="False">
                            <Setter Property="Visibility" Value="Visible"/>
                          </DataTrigger>
                        </Style.Triggers>
                      </Style>
                    </ComboBox.Style>                      
                  </ComboBox>
                </Grid>
              </DockPanel>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
    </ComboBox.Style>

This preserves the selected item, selected index, and selected value, just as you want. In fact, it does this a little too well; there's not actually a way of telling that the user deactivated the combo box, since there's no property on ComboBox that exposes this information. I'd probably actually implement this as a custom control derived from ComboBox that exposed the value of the check box as an IsActive property. There are lots of other ways to do it.

Robert Rossney
  • 94,622
  • 24
  • 146
  • 218
  • Neat idea although the solution proposed by HCL and that I elaborated on in an update to my question is still a lot shorter code than this and achieves the same result. I'm curious of there is any other benefits to your technique or his or vise-verse. Either way, thanks for contributing your answer. – jpierson Jan 20 '11 at 01:00
  • 1
    My technique lets you swap in a different visual if the combo box is inactive, but that's really the only advantage I can think of in this particular case. – Robert Rossney Jan 20 '11 at 19:43