Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a WPF ComboBox display alternative text when its selection is null?

G'day!

I want my WPF ComboBox to display some alternative text when its data-bound selection is null.

The view model has the expected properties:

public ThingoSelectionViewModel : INotifyPropertyChanged {
    public ThingoSelectionViewModel(IProvideThingos) {
        this.Thingos = IProvideThingos.GetThingos();
    }

    public ObservableCollection<Thingo> Thingos { get; set; }

    public Thingo SelectedThingo { 
        get { return this.selectedThingo; }
        set { // set this.selectedThingo and raise the property change notification
    }

    // ...

}

The view has XAML binding to the view model in the expected way:

<ComboBox x:Name="ComboboxDrive" SelectedItem="{Binding Path=SelectedThingo}"
          IsEditable="false" HorizontalAlignment="Left" MinWidth="100" 
          IsReadOnly="false" Style="{StaticResource ComboboxStyle}"
          Grid.Column="1" Grid.Row="1" Margin="5" SelectedIndex="0">
    <ComboBox.ItemsSource>
        <CompositeCollection>
        <ComboBoxItem IsEnabled="False">Select a thingo</ComboBoxItem>
        <CollectionContainer 
            Collection="{Binding Source={StaticResource Thingos}}" />
        </CompositeCollection>
    </ComboBox.ItemsSource>
</ComboBox>

The ComboBoxItem wedged into the top is a way to get an extra item at the top. It's pure chrome: the view model stays pure and simple. There's just one problem: the users want "Select a thingo" displayed whenever the ComboBox' selection is null.

The users do not want a thingo selected by default. They want to see a message telling them to select a thingo.

I'd like to avoid having to pollute the viewmodel with a ThingoWrapper class with a ToString method returning "Select a thingo" if its .ActualThingo property is null, wrapping each Thingo as I populate Thingos, and figuring out some way to prevent the user from selecting the nulled Thingo.

Is there a way to display "Select a thingo" within the ComboBox' boundaries using pure XAML, or pure XAML and a few lines of code in the view's code-behind class?

like image 857
Garth Kidd Avatar asked May 25 '10 02:05

Garth Kidd


People also ask

What happens when we select a value from a ComboBox in WPF?

Selected and Current Item Text property of ComboBox represents the text of the current selected item in a ComboBox. SelectedItem represents the first item in the currently selected items in a ComboBox. SelectedValue represents the value of the currently selected item in a ComboBox.

How do I change the ComboBox style in WPF?

In visual studio, open WPF designer, select combo box control, then right click combo box control and select Edit template, then select Edit a Copy. This will create a style template, you can modify it as you need.

How do I change the color of a ComboBox in WPF?

Right click on the ComboBox element in the design view in Visual Studio again and then select the “Edit Additional Templates” option followed by the “Edit Generated Item Container (ItemContainerStyle)” and “Edit a copy…” options.

What is ComboBox in WPF?

Advertisements. A combobox is a selection control that combines a non-editable textbox and a drop-down listbox that allows users to select an item from a list. It either displays the current selection or is empty if there is no selected item.


1 Answers

How strict is your MVVM requirement? Can you have a little code-behind in the view?

Perhaps you could contain the ComboBox in a grid, something like this:

<Grid>
    <ComboBox x:Name="ComboBoxControl"
              SelectionChanged="ComboBoxControl_SelectionChanged"
              HorizontalAlignment="Left" VerticalAlignment="Top" 
              MinWidth="{Binding ElementName=UnselectedText, Path=ActualWidth}">
        <ComboBoxItem>One</ComboBoxItem>
        <ComboBoxItem>Two</ComboBoxItem>
        <ComboBoxItem>Three</ComboBoxItem>
    </ComboBox>
    <TextBlock IsHitTestVisible="False" 
               x:Name="UnselectedText" 
               HorizontalAlignment="Left" 
               Text="Select an option..." 
               VerticalAlignment="Top" Margin="4" 
               Padding="0,0,30,0" />
</Grid>

Then, in the code-behind, insert some logic in an event handler:

Private Sub ComboBoxControl_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs)
    If ComboBoxControl.SelectedIndex = -1 Then
        UnselectedText.Visibility = Windows.Visibility.Visible
    Else
        UnselectedText.Visibility = Windows.Visibility.Hidden
    End If
End Sub

Setting the IsHitTestVisible="False" DependencyProperty on the TextBlock lets mouse events through so that you can click on the ComboBox, and setting the visibility to Hidden in the code-behind keeps the layout of a default ComboBox's appearance from jumping around when the prompt text is hidden.

like image 99
Rob Perkins Avatar answered Sep 23 '22 19:09

Rob Perkins