#1,198 – Selectively Enabling Child Elements in a Disabled Panel

When you set IsEnabled to false in a panel, all child elements in that panel are disabled. You cannot selectively enabled child elements in the panel.

You may, however, want to selectively enable child elements in a panel. (E.g. Disable entire panel, then set IsEnabled=True, IsReadOnly=True on TextBox controls so that you can copy text).

One possible solution is to define a new control that inherits from TextBox and does not coerce the value of IsEnabled.

    public class CanEnableTextBox : TextBox
    {
        static CanEnableTextBox()
        {
            CanEnableTextBox.IsEnabledProperty.OverrideMetadata(typeof(CanEnableTextBox),
                new System.Windows.UIPropertyMetadata(true,
                    new PropertyChangedCallback(IsEnabledPropertyChanged),
                    new CoerceValueCallback(CoerceIsEnabled)));

        }

        private static void IsEnabledPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
        {
            // Overriding PropertyChanged results in merged metadata, which is what we want--
            // the PropertyChanged logic in UIElement.IsEnabled will still get invoked.
        }

        private static object CoerceIsEnabled(DependencyObject source, object value)
        {
            return value;
        }
    }

You can now use this control in a panel that has IsEnabled set to false and you’ll be able to set IsEnabled on the child TextBox.

#1,066 – Elements Must Be Visible and Enabled to Fire Events

Events fired from user interface elements in WPF are typically routed events, firing events from elements up or down the logical tree after the source element has fired the event.

A user interface element must be both visible (Visibility = Visible) and enabled (IsEnabled = true) in order to fire an event.  If an element is not visible or is disabled, the topmost element beneath the element may fire the event instead.

Below, if we set IsEnabled on the Label to false, its MouseDown event will not fire and the StackPanel will become the source of the event instead.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Events" Width="208" Height="183"
        MouseDown="Window_MouseDown">

    <StackPanel MouseDown="StackPanel_MouseDown"
                Background="AliceBlue" Margin="10">
        <Label Content="Label" Background="Orange" Margin="10"
               MouseDown="Label_MouseDown"
               IsEnabled="False"/>
    </StackPanel>
</Window>

When we click on the Label, the StackPanel fires the MouseDown event, followed by the parent Window.

1066-002

1066-001

#932 – Making a TextBox Read-Only or Disabled

You can control a couple of different things with the IsEnabled and IsReadOnly properties of a TextBox.

  • IsEnabled – When false, user can’t interact with the control in any way and the control is greyed out.  (Default is true)
  • IsReadOnly – When true, user can’t edit or enter text, but can still scroll, select text and copy.

Typical combinations:

  • IsEnabledtrue, IsReadOnly = false — standard behavior, editable text
  • IsEnabled = true, IsReadOnly = true — read-only text, user can scroll/copy
  • IsEnabled = false — user can’t interact with TextBox at all
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <TextBox Name="txtMain" Margin="5"
                 Text="{Binding SomeText}"
                 TextWrapping="Wrap"
                 VerticalScrollBarVisibility="Auto"
                 IsReadOnly="{Binding ElementName=chkReadOnly, Path=IsChecked}"
                 IsEnabled="{Binding ElementName=chkEnabled, Path=IsChecked}"/>
        <StackPanel Orientation="Horizontal" Grid.Row="1">
            <CheckBox Name="chkReadOnly" Content="IsReadOnly" />
            <CheckBox Name="chkEnabled" Content="IsEnabled" />
        </StackPanel>
    </Grid>

932-001
932-002
932-003

#644 – Disabling and Hiding Controls

You can disable a control by setting its IsEnabled property to false.  Disabled controls cannot receive input, but are still displayed in the user interface, typically greyed out.

Below is an example of some typical controls, showing what they looked like when enabled vs. disabled.

In addition to disabling a control, you can also make the entire control invisible, using the Visibility property.  Controls that are not visible can be one of:

  • Hidden – Control is not visible, but it still takes up space in the user interface.  I.e. There is whitespace where the control would be if it were visible
  • Collapsed – Control is not present at all in the user interface and neighboring controls fill in the space where the control would be if it were visible

 

 

#643 – Disabled Controls Cannot Get Focus

When a control is disabled, i.e. its IsEnabled property is set to false, the user cannot give the control keyboard focus by clicking on it.  The control also cannot gain focus by use of the tab key.  Disabled controls cannot get focus, even if both their Focusable and IsTabStop properties are set to true.

    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <TextBox Text="IsEnabled=true" IsEnabled="True" Width="140" Margin="10"/>
            <TextBox Text="IsEnabled=false" IsEnabled="False" Width="140" Margin="10"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Button Content="IsEnabled=true" IsEnabled="True" Margin="10"/>
            <Button Content="IsEnabled=false" IsEnabled="False" Margin="10"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <ComboBox IsEnabled="True" Margin="10" SelectedIndex="0">
                <ComboBoxItem Content="McClellan"/>
                <ComboBoxItem Content="Hooker"/>
                <ComboBoxItem Content="Meade"/>
            </ComboBox>
            <ComboBox IsEnabled="False" Margin="10" SelectedIndex="0">
                <ComboBoxItem Content="McClellan"/>
                <ComboBoxItem Content="Hooker"/>
                <ComboBoxItem Content="Meade"/>
            </ComboBox>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <Label Content="IsEnabled=true" IsEnabled="True" Margin="10"/>
            <Label Content="IsEnabled=false" IsEnabled="False" Margin="10"/>
        </StackPanel>
    </StackPanel>