#353 – Binding a Three-State CheckBox to a Nullable Bool

Because a three-state CheckBox can take on any one of three different values, its current value can’t be represented by a simple bool.  A bool can only take on true and false values.

A three-state CheckBox can instead be bound to a nullable bool (represented by bool?), which can take on three different values.

  • true  (checked)
  • false  (not checked)
  • null  (indeterminate)

In the example below, we bind a CheckBox control’s IsChecked property to a nullable bool property.

        <CheckBox Content="Happy" IsChecked="{Binding IsHappy}" IsThreeState="True"/>

In the code-behind, we define the property and set the main window’s data context.

        // Nullable bool - can be true, false or null
        public bool? IsHappy { get; set; }

		public MainWindow()
		{
			this.InitializeComponent();
            this.DataContext = this;
        }

#352 – Use IsThreeState Property to Create a CheckBox that Has an Indeterminate State

The CheckBox control normally has two states–checked or unchecked.  The current state can be determined by reading the IsChecked property, which can take on the values true and false.

You can also use a CheckBox to represent an indeterminate value–a value that is neither true nor false.  To indicate that a CheckBox can have three states (checked, not checked and indetermine), set the IsThreeState property to true.

        <CheckBox Content="Happy" IsThreeState="True"/>

At run-time, you’ll notice that the CheckBox will cycle through the three states. A solid box rather than a check mark indicates the indeterminate state.

In code, you can read the IsChecked property to determine the state.  IsChecked is a nullable bool and can have one of the values:

  • true  (checked)
  • false  (not checked)
  • null  (indeterminate)

#351 – Binding a CheckBox’s IsChecked Property to a Boolean Variable

Instead of handling the Checked and Unchecked events of a CheckBox and then setting a boolean variable to represent the current state, you’ll most often just use data binding to bind the IsChecked property to a boolean variable.

In the example below, we have three CheckBox controls, each bound to a boolean property.

        <Label Content="Things my dog can do:"/>
        <CheckBox Content="Sit" IsChecked="{Binding CanSit}"/>
        <CheckBox Content="Stay" IsChecked="{Binding CanStay}"/>
        <CheckBox Content="Fetch" IsChecked="{Binding CanFetch}"/>
        <Button Content="Test" Click="Test_Click"/>

In the code-behind, we define the boolean properties that we can bind to and then set the data context to refer to the parent class.

        public bool CanSit { get; set; }
        public bool CanStay { get; set; }
        public bool CanFetch { get; set; }

		public MainWindow()
		{
			this.InitializeComponent();
            this.DataContext = this;
        }

        private void Test_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(string.Format("Sit: {0}, Stay: {1}, Fetch: {2}", CanSit, CanStay, CanFetch));
        }

#350 – CheckBox Basics

The CheckBox control allows a user to toggle the state of something in an application.  The user uses the left mouse button to check/uncheck the control, turning something on or off.

You specify a label for each CheckBox using its Content property.

    <StackPanel HorizontalAlignment="Center">
        <Label Content="Things my dog can do:"/>
        <CheckBox Content="Sit"/>
        <CheckBox Content="Stay"/>
        <CheckBox Content="Fetch"/>
    </StackPanel>

The IsChecked property indicates whether a CheckBox is currently checked.  It can be read from or written to.  You can also use data binding to bind the IsChecked property to a boolean variable.

The Checked event fires when a user checks the CheckBox.  The Unchecked event fires when a user unchecks the CheckBox.  The Click event fires whenever the user checks or unchecks the CheckBox.

#349 – Predefined Command Objects, Part II

When you associate a button or menu item to a command object by setting its Command property, you typically associate the control with a preexisting command object.  You can also create your own command, e.g. an instance of a RoutedUICommand.

The preexisting commands listed below are all static properties, pointing to instances of a RoutedUICommand.

  • In NavigationCommands
    • BrowseBack
    • BrowseForward
    • BrowseHome
    • BrowseStop
    • DecreaseZoom
    • Favorites
    • FirstPage
    • GoToPage
    • IncreaseZoom
    • LastPage
    • NavigateJournal
    • NextPage
    • PreviousPage
    • Refresh
    • Search
    • Zoom
  • In EditingCommands
    • AlignCenter
    • AlignJustify
    • AlignLeft
    • AlignRight
    • Backspace
    • CorrectSpellingError
    • DecreaseFontSize
    • DecreaseIndentation
    • Delete
    • DeleteNextWord
    • DeletePreviousWord
    • EnterLineBreak
    • EnterParagraphBreak
    • IgnoreSpellingError
    • IncreaseFontSize
    • IncreaseIndentation
    • MoveDownByLine
    • MoveDownByPage
    • MoveDownByParagraph
    • MoveLeftByCharacter
    • MoveLeftByWord
    • MoveRightByCharacter
    • MoveRightByWord
    • MoveToDocumentEnd
    • MoveToDocumentStart
    • MoveToLineEnd
    • MoveToLineStart
    • MoveUpByLine
    • MoveUpByPage
    • MoveUpByParagraph
    • SelectDownByLine
    • SelectDownByPage
    • SelectDownByParagraph
    • SelectLeftByCharacter
    • SelectLeftByWord
    • SelectToDocumentEnd
    • SelectToDocumentStart
    • SelectToLineEnd
    • SelectToLineStart
    • SelectUpByLine
    • SelectUpByPage
    • SelectUpByParagraph
    • TabBackward
    • TabForward
    • ToggleBold
    • ToggleBullets
    • ToggleInsert
    • ToggleItalic
    • ToggleNumbering
    • ToggleSubscript
    • ToggleSuperscript
    • ToggleUnderline

#348 – Predefined Command Objects, Part I

When you associate a button or menu item to a command object by setting its Command property, you typically associate the control with a preexisting command object.  You can also create your own command, e.g. an instance of a RoutedUICommand.

The preexisting commands listed below are all static properties, pointing to instances of a RoutedUICommand.

  • In ApplicationCommands
    • CancelPrint
    • Close
    • ContextMenu
    • Copy
    • CorrectionList
    • Cut
    • Delete
    • Find
    • Help
    • New
    • Open
    • Paste
    • Print
    • PrintPreview
    • Properties
    • Redo
    • Replace
    • Save
    • SaveAs
    • SelectAll
    • Stop
    • Undo
  • In ComponentCommands
    • ExtendSelectionDown
    • ExtendSelectionLeft
    • ExtendSelectionRight
    • ExtendSelectionUp
    • MoveDown
    • MoveFocusBack
    • MoveFocusDown
    • MoveFocusForward
    • MoveFocusPageDown
    • MoveFocusPageUp
    • MoveFocusUp
    • MoveLeft
    • MoveRight
    • MoveToEnd
    • MoveToHome
    • MoveToPageDown
    • MoveToPageUp
    • MoveUp
    • ScrollByLine
    • ScrollPageDown
    • ScrollPageLeft
    • ScrollPageRight
    • ScrollPageUp
    • SelectToEnd
    • SelectToHome
    • SelectToPageDown
    • SelectToPageUp
  • In MediaCommands
    • BoostBass
    • ChannelDown
    • ChannelUp
    • DecreaseBass
    • DecreaseMicrophoneVolume
    • DecreaseTreble
    • DecreaseVolume
    • FastForward
    • IncreaseBass
    • IncreaseMicrophoneVolume
    • IncreaseTreble
    • IncreaseVolume
    • MuteMicrophoneVolume
    • MuteVolume
    • NextTrack
    • Pause
    • Play
    • PreviousTrack
    • Record
    • Rewind
    • Select
    • Stop
    • ToggleMicrophoneOnOff
    • TogglePlayPause

More commands coming next time–in NavigationCommands and EditingCommands.

#347 – How to Set Content Property for Button Based on Command

When you set the Command property of a MenuItem, the menu item automatically picks up a label from the command object, so you don’t need to set the menu item’s Header property.  Unfortunately, this doesn’t work for Button controls.

If you do want to set a Button control’s Content property based on the Text property of the associated command, you can do this in either XAML or code.

To set Content based on command in XAML:

        <Button Content="{Binding RelativeSource={RelativeSource Self}, Path=Command.Text}"
                Command="ApplicationCommands.Open"
                VerticalAlignment="Center" Padding="10,5" Margin="5"/>

To set the Content in code:

            btnOpen.Content = ApplicationCommands.Open.Text;

#346 – No Need to Set Header Property for MenuItem When Using Commands

If you use one of the preexisting RoutedUICommand objects for a WPF command, e.g. ApplicationCommands.Open, you’ll notice that the RoutedUICommand instance has a Text property.  This property in the command is used to set the label appearing on any MenuItem instances that have attached to the command by setting their Command property.  You don’t need to set the menu item’s Header property explicitly.

    <Window.ContextMenu>
        <ContextMenu>
            <MenuItem Command="ApplicationCommands.Open"/>
            <MenuItem Command="ApplicationCommands.Close"/>
            <MenuItem Command="ApplicationCommands.New"/>
        </ContextMenu>
    </Window.ContextMenu>


Notice that the text for each menu item is automatically filled in, since the text strings are defined in the RoutedUICommand object.  Also notice that some of the commands also define key gestures (e.g. Ctrl+O) for executing the command.

#345 – WPF Command Model is Preferred over Traditional Event Handler Model

In an application, you often need to execute some code in response to a user action.  In WPF, you can use the new command model to respond to user actions or you can use the event handler model that Windows Forms used.

In the event handler model, you wire up event handlers to the code that does the actual work.

With this approach, you still have to add all of the individual event handlers and you need to write code to manage state, i.e. figure out when the user is allowed to click the buttons/menus and enable/disable them.

In the WPF command model, a single command object is bound to the handler code and each control links to that command.  The command object also adds support for state.

So the benefits of the WPF command model are:

  • Less plumbing code to write (no event handlers)
  • Automatically handle control enabled/disabled state

#344 – The CommandBinding CanExecute Event Determines Whether a Button is Enabled

When you associate a button’s Command property with a CommandBinding object,and bind the CommandBinding object to both Executed and CanExecute handlers, the Button control will automatically toggle between enabled/disabled, depending on the code in the CanExecute method.

Suppose we create two buttons, binding them to open/close commands.

    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        <Button Content="Open" Command="ApplicationCommands.Open"
                VerticalAlignment="Center" Padding="10,5" Margin="5"/>
        <Button Content="Close" Command="ApplicationCommands.Close"
                VerticalAlignment="Center" Padding="10,5" Margin="5"/>
    </StackPanel>

Then we create a CommandBinding and associated handlers.

		public MainWindow()
		{
			this.InitializeComponent();

            CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, Open_Executed, Open_CanExecute));
            CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, Close_Executed, Close_CanExecute));
        }

        private bool isOpen = false;

        public void Open_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Open");
            isOpen = true;
        }

        public void Open_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = !isOpen;
        }

        public void Close_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Close");
            isOpen = false;
        }

        public void Close_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = isOpen;
        }

The buttons will now automatically be enabled/disabled, depending on the value of isOpen.

Follow

Get every new post delivered to your Inbox.

Join 351 other followers