Item selection

Unlike a ListBox, a TreeView does not have a SelectedItem. Instead, we have to data bind the IsSelected property of the TreeViewItem to the view model. This can be done globally by defining a style.

<Window.Resources>
    <Style TargetType="TreeViewItem">
        <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
    </Style>
</Window.Resources>

Then we create an IsSelected property on the view model.

public bool IsSelected
{
    get { return _selection.SelectedSurvey == _survey; }
    set { _selection.SelectedSurvey = value ? _survey : null; }
}

The TreeViewItem will get this property to determine whether the item appears selected. It will set this property when the user selects an item.

Selection model

The IsSelected property uses a selection model to record the selected object. This object records the user's current point-of-view as they navigate the data model. As such, the selection model contains references to data model objects.

public class GameSelectionModel
{
    private Independent<Survey> _selectedSurvey =
        new Independent<Survey>();

    public Survey SelectedSurvey
    {
        get { return _selectedSurvey.Value; }
        set { _selectedSurvey.Value = value; }
    }
}

Not only is the IsSelected property of the TreeViewItem dependent upon the selection model, but so are the command buttons. Because of this shared dependency, the command buttons are enabled and disabled as the user selects items in the tree.

public ICommand NewAnswer
{
    get
    {
        return MakeCommand
            .When(() => _selection.SelectedSurvey != null)
            .Do(() => _selection.SelectedSurvey.NewAnswer());
    }
}

When the SelectedSurvey is not null, the command button is enabled. When clicked, it adds a new answer to the selected survey.

The selection model is not just set by the user. It can also be affected by code. For example, when the user creates a new survey, we want that to become the selected one.

public ICommand NewSurvey
{
    get
    {
        return MakeCommand
            .Do(() => _selection.SelectedSurvey = _game.NewSurvey());
    }
}

The selection model bridges user selection and application behavior.