#852 – Setting a Three-State CheckBox to an Indeterminate Value

A three-state CheckBox can take on one of three values: true, false, or indeterminate.  You can use data binding to get/set the value of a three-state CheckBox, binding the control to a nullable bool.

You can also explicitly set the value of a CheckBox, in either XAML or code.

To set a CheckBox to an indeterminate value in code, just set its IsChecked property to null.

            chkPie.IsChecked = null;

852-001
To set a CheckBox to an indeterminate value in XAML, set its IsChecked property to {x:Null}.

        <CheckBox Name="chkPie" Content="I Like Pie" IsThreeState="True"
                  IsChecked="{x:Null}"/>
Advertisement

#851 – Using RepeatButtons to Move Something

The RepeatButton functions like a regular Button, but continuously fires Click events while the button remains depressed.

One possible use for a RepeatButton is to move something while the user holds the mouse button down.

Below, we use a pair of RepeatButtons to move a picture around a Canvas.

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Canvas Grid.ColumnSpan="2">
            <Image Source="Augustus.jpg" Height="100"
                   Canvas.Left="{Binding PictureLeft}" Canvas.Top="20"/>
        </Canvas>

        <RepeatButton Grid.Row="1" Content="Left"
                      Padding="10,5" Margin="5" HorizontalAlignment="Center"
                      Click="rptLeft_Click"/>
        <RepeatButton Grid.Row="1" Grid.Column="1" Content="Right"
                      Padding="10,5" Margin="5" HorizontalAlignment="Center"
                      Click="rptRight_Click"/>
    </Grid>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            this.InitializeComponent();
            this.DataContext = this;
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }

        private int pictureLeft = 0;
        public int PictureLeft
        {
            get { return pictureLeft; }
            protected set
            {
                pictureLeft = value;
                RaisePropertyChanged("PictureLeft");
            }
        }

        private void rptLeft_Click(object sender, RoutedEventArgs e)
        {
            PictureLeft -= 5;
        }

        private void rptRight_Click(object sender, RoutedEventArgs e)
        {
            PictureLeft += 5;
        }
    }

851-001

#850 – Specifying a Delay and Interval for a RepeatButton

If you hold the left mouse button down after clicking on a RepeatButton control, it will repeatedly fire Click events.

By default, a RepeatButton waits 1/2 sec (500 ms) after firing the first Click event and then begins firing Click events every 33 ms (about 30 times per second).

You can configure these values using the following properties of the RepeatButton:

  • Delay – Initial delay to wait, after first Click event, before repeatedly firing additional events
  • Interval – Time to wait between Click events

Note that the interval between events includes whatever time is spent in executing the Click event handler, unless you perform any required processing on a background thread.  In other words, the clock begins ticking again towards the next interval after you exit from the Click handler for the previous tick.

#849 – You Can Hold a RepeatButton Down

A Button fires its Click event when you press and release the left mouse button.  A RepeatButton, on the other hand, fires Click events continuously, as long as you continue holding the left mouse button down.

For example:

        <RepeatButton Content="Hold Me Down"
                      HorizontalAlignment="Center"
                      Margin="10" Padding="10,5"
                      Click="RepeatButton_Click"/>
        <TextBlock Text="{Binding MyCounter, Mode=OneWay}"
                   HorizontalAlignment="Center"
                   FontSize="48" Margin="20"/>

In the code-behind, we increment a counter every time the Click event is fired.

    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            this.InitializeComponent();
            this.DataContext = this;
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }

        private int myCounter = 0;
        public int MyCounter
        {
            get { return myCounter; }
            protected set
            {
                if (value != myCounter)
                {
                    myCounter = value;
                    RaisePropertyChanged("MyCounter");
                }
            }
        }

        private void RepeatButton_Click(object sender, RoutedEventArgs e)
        {
            MyCounter++;
        }
    }

The number increases while we hold the left mouse button down.
849-001

#848 – IsDefaulted vs. IsDefault for a Button

The IsDefault property can be set for a Button to indicate that you’d like the button to act as a default button for a window, i.e. activate when the user presses the ENTER key.

The IsDefaulted property is a read-only property that indicates if a Button is currently acting as the default button for a window, meaning that it would activate if the user pressed ENTER at this moment.

IsDefaulted will be true if all of the following is true:

  • IsDefault for the Button is set to true
  • Some other control currently has focus
  • The control that currently has focus does not itself handle the ENTER key

 

#847 – Default Button Behavior Depends on Focus

When you set the IsDefault property of a Button to true, the user can activate the button by pressing the ENTER key.

The default behavior of a Button, however, will depend on which control in the window has focus when the user presses ENTER.  If the control that has focus can itself handle the ENTER key, that control will activate when ENTER is pressed, rather than a Button that has IsDefault set to true.

In the example below, the second TextBox has AcceptsReturn set to true and the “Save” button has IsDefault set to true.  Because both the second TextBox and the Cancel button can themselves handle the ENTER key, the “Save” button will only activate on ENTER if the first TextBox has focus when ENTER is pressed.

847-001

847-002

#846 – Including an Underscore Character in a Label

When you include an underline ‘_’ character in the Content property of a Label, the underline character will be used to determine the access key for the label.  If you want to actually have a underline character show up in your user interface, you need to use a double underline ‘__’ sequence for the underline character.

    <StackPanel Orientation="Horizontal">
        <Label Content="Enter Your Super__Cool _Nickname"
               Target="{Binding ElementName=txtName}"
               VerticalAlignment="Center"/>
        <TextBox Name="txtName" Width="150"
                 VerticalAlignment="Center"/>
    </StackPanel>

846-001

#845 – Display Ellipsis in TextBlock to Indicate that Content Doesn’t Fit

By default, when the text in a TextBlock does not fit the available space, the text is simply clipped against the boundaries of the available space.

849-001

You can, however, use the TextTrimming property to cause an ellipsis (three dots) to be displayed when the TextBlock contains more text than can be displayed.

Possible values for TextTrimming area:

  • None – no ellipsis, text is clipped  (the default)
  • CharacterEllipsis – display as many characters as possible, followed by an ellipsis
  • WordEllipsis – display as many words as possible, followed by an ellipsis
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <TextBlock Text="{StaticResource someText}"
                    TextWrapping="Wrap" TextTrimming="CharacterEllipsis"
                    Margin="10"/>
        <StackPanel Grid.Row="1" Background="AliceBlue"/>
    </Grid>

849-002

#844 – The TextBlock Supports Hyphenation

If a TextBlock is set to wrap text automatically, you can also tell it to automatically hyphenate by setting its IsHyphenationEnabled property to true.

In the example below, the first two blocks of text are left justified, but the second block has hyphenation enabled.

The third block enables hyphenation for a justified block of text.

        <TextBlock Text="{StaticResource someText}"
                   TextWrapping="Wrap"
                   TextAlignment="Left"
                   Margin="10"/>
        <TextBlock Text="{StaticResource someText}"
                   TextWrapping="Wrap"
                   IsHyphenationEnabled="True"
                   TextAlignment="Left"
                   Margin="10"/>
        <TextBlock Text="{StaticResource someText}"
                   TextWrapping="Wrap"
                   TextAlignment="Justify"
                   IsHyphenationEnabled="True"
                   Margin="10"/>

844-001

#843 – Text Justification in a TextBlock

In typography, justification is the alignment of the edges of a block of text.  Text can be “flush left”, indicating that the left edges of the lines are aligned with each other and the right edges are ragged–i.e. not aligned.  Text can also be “flush right” (right ends of lines are aligned), “justified” (both edges line up), or centered (both edges ragged).

WPF allows justification of text using the TextBlock element.  You specify justification in a TextBlock using the TextAlignment property, setting it to one of: Left, Right, Center or Justify.

        <TextBlock Text="{StaticResource someText}"
                   TextWrapping="Wrap"
                   TextAlignment="Left"
                   Margin="10"/>
        <TextBlock Text="{StaticResource someText}"
                   TextWrapping="Wrap"
                   TextAlignment="Right"
                   Margin="10"/>
        <TextBlock Text="{StaticResource someText}"
                   TextWrapping="Wrap"
                   TextAlignment="Center"
                   Margin="10"/>
        <TextBlock Text="{StaticResource someText}"
                   TextWrapping="Wrap"
                   TextAlignment="Justify"
                   Margin="10"/>

843-001