#976 – SelectedItem Binding on an ItemsControl is Two-Way

When you use data binding to associate a property in your data context to the currently selected item in an ItemsControl (e.g. a ListBox), the data binding is by default two-way.  That is:

  • When the user selects a new item in the list, the value of the bound property changes
  • If the value of the bound property changes, the selection in the list changes

Suppose that we bind the ItemsSource of a ListBox to a collection of Actor objects and that we bind the SelectedItem property of the ListBox to a SelectedActor property in our data context (of type Actor).

When the user selects an item, the value of the SelectedActor property changes.  (Below, the labels are bound to sub-properties of SelectedActor).

976-003

If we instead change the value of SelectedActor (e.g. in code-behind after clicking a button), the currently selected item in the ListBox will change.

976-004

Advertisements

#975 – SelectedValue and SelectedValuePath for a ListBox

You can set the SelectedValuePath property of a ListBox to the desired property of each item in the list that should be bound to the SelectedValue property.

For example, suppose that we store a collection of Actor objects in a ListBox, e.g. by using data binding to bind the items in the ListBox to a collection of Actor objects.  We can then do the following:

  • Set SelectedValuePath to “FullName” — a property of Actor
  • Use data binding to set SelectedValue to “SelectedActor” property of the data context

Now when the user selects an item in the list, the SelectedActor property in our data context will be set to the FullName of the selected actor.

        <ListBox Margin="15" Width="200" Height="150"
                 ItemsSource="{Binding ActorList}"
                 SelectedValuePath="FullName"
                 SelectedValue="{Binding SelectedActor}"/>
        <TextBlock Text="{Binding SelectedActor}"
                   HorizontalAlignment="Center"/>

975-001

#974 – Properties for Retrieving Selected Items in a ListBox

You can use the following properties to find out which items in a ListBox are selected:

  • If a single item is selected:
    • SelectedIndex is the 0-based index of the selected item
    • SelectedItem refers to the selected item
    • SelectedItems is a list containing the single selected item
  • If multiple items are selected:
    • SelectedIndex is the 0-based index of the first item that the user selected
    • SelectedItem refers to the first item that the user selected
    • SelectedItems is a list containing all selected items
  • If no items in the ListBox are selected:
    • SelectedIndex is -1
    • SelectedItem is null
    • SelectedItems is null

974-002

974-003

974-001

 

#973 – Keyboard Shortcuts for a ListBox

You can use any of the following keyboard shortcuts when interacting with a ListBox at run-time (this assumes that the ListBox has keyboard focus):

  • Up/Down arrow keys – move to previous /next item
  • Page Up / Page Down – move to item on previous / next page (based on size of ListBox)
  • Home / End – move to first / last item in last
  • Enter single character – move to next item that begins with that character
  • Enter sequence of characters – move to next item that begins with that sequence
  • If the SelectionMode is Single or Extended
    • Moving to another item selects it (and unselects previous)
    • Spacebar – select the current item (if not already selected)
    • Ctrl + Spacebar – unselect the current item
  • If the SelectionMode is Multiple
    • Moving to another item does not select it
    • Spacebar toggles current item as selected/unselected
  • If the SelectionMode is Extended
    • Holding down the Shift key while moving to another item adds to selection

#972 – How ListBox Items Are Rendered

The rules for how WPF will render items contained in a ListBox are as follows:

  • If the item derives from UIElement, it is rendered normally, using the layout system
  • Otherwise, the item’s ToString method is called and the resulting string is displayed

In the example below, the first two items in the ListBox derive from UIElement and are therefore rendered as controls.  The third item is a simple .NET object, so its ToString method is called.

        <ListBox Margin="15" Width="250" Height="250">
            <TextBox Text="Enter text here" Width="150"/>
            <Label Content="A label" FontFamily="Times New Roman"
                   FontSize="16"/>
            <local:Actor FullName="Marty Feldman" BirthYear="1934" DeathYear="1982"/>
        </ListBox>

972-001

#971 – Items Property is a Content Property

Every control that derives from ItemsControl (including the ListBox) has an Items property that stores the collection of items represented by the control.

The Items property of an ItemsControl is also its content property.  This means that you can set the value of the Items property directly in XAML by specifying a list of child elements for the control that derives from ItemsControl.

For example, you can explicitly specify the child elements using property element syntax:

        <ListBox Margin="15" Width="250" Height="250">
            <ListBox.Items>
                <ListBoxItem Content="Thing 1"/>
                <ListBoxItem Content="Thing 2"/>
            </ListBox.Items>
        </ListBox>

Because the Items property is a content property, you can be more concise, doing the following:

        <ListBox Margin="15" Width="250" Height="250">
            <ListBoxItem Content="Thing 1"/>
            <ListBoxItem Content="Thing 2"/>
        </ListBox>

#970 – Avoid Working Directly with Items Collection

When you use a ListBox (or any other ItemsControl), you’ll most often populate the control by binding the ItemsSource property of the control to a collection.  The Items property of the control can then be examined, if you want to look at the individual items in the collection.

In practice, however, you’ll work directly with the collection that the ListBox is bound to, rather than working with the Items property.  For example:

  • To add items, add them to the underlying collection
  • To remove items, remove them from the underlying collection
  • To change an item, change the corresponding item in the underlying collection

The example below adds a new Actor to a bound collection when a button is clicked.  Note that the ListBox is updated immediately.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ActorList.Add(new Actor("Marty Feldman", 1934, 1982, "Young Frankenstein"));
        }

970-001