2

I want to set a default text to my ComboBox, something like this "Please Select". For WPF it can be done using CompositeCollection as below but CompositeCollection is not available in UWP, so is there any alternative for it?

<ComboBox SelectedIndex="0">
    <ComboBox.ItemsSource>
        <CompositeCollection>
            <ListBoxItem>Please Select</ListBoxItem>
            <CollectionContainer Collection="{Binding Source={StaticResource YOURDATASOURCE}}" />
        </CompositeCollection>
    </ComboBox.ItemsSource>
</ComboBox>
Dishant
  • 1,545
  • 12
  • 29

2 Answers2

2

I want to set a default text to my ComboBox, something like this "Please Select".

ComboBox has PlaceholderText property that use to display in the control until the value is changed by a user action or some other operation.

<ComboBox  PlaceholderText="Please Select" Width="200">
<x:String>Blue<x:String>
<x:String>Green<x:String>
<x:String>Red<x:String>
<x:String>Yellow<x:String>
</ComboBox>

Update

If you need an item to be the default option, you could use SelectedItem or SelectIndex to realize.

Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
  • Thanks. But what in case if you wan't to deselect the item from the ComboBox? – Dishant Aug 16 '18 at 04:03
  • `PlaceholderText` is just used to illustrate the contents of combobox and it won't appear in your items. – Nico Zhu Aug 16 '18 at 05:48
  • So there is no alternative if I want this in my actual list? I am using MVVM pattern so instead of adding this default value in VM is there any alternative via XAML? – Dishant Aug 16 '18 at 21:38
  • If you need an item to be the default option, you could use [SelectedItem or SelectIndex](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.combobox.selecteditem?view=netframework-4.7.2#examples) to realize. – Nico Zhu Aug 17 '18 at 02:03
  • Actually, my point is that at first default selection will be "Please Select" but once a user selects any item, say Green from your example and later want's to clear the selection what are the possible options? – Dishant Aug 17 '18 at 02:27
  • I don't know what is mean **and later want's to clear the selection what are the possible options?** – Nico Zhu Aug 17 '18 at 02:32
  • If you have a selected item then clear others, you could remove the others in your viewmode. I understand it right? – Nico Zhu Aug 17 '18 at 02:34
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/178173/discussion-between-nico-zhu-msft-and-dishant). – Nico Zhu Aug 17 '18 at 02:36
2

After spending a couple of hours to search for the solution, I came across this post which tackle this problem in a nice way by appending the Clear(X) button inside the ComboBox beside the selected item. The solution provided is in WPF, so if anybody want's this for their UWP project please refer to below code:

Custom ComboBox Style:

<Style TargetType="ComboBox" x:Key="ComboBoxWithClearButtonStyle">
        <Setter Property="Padding" Value="12,5,0,7" />
        <Setter Property="MinWidth" Value="{ThemeResource ComboBoxThemeMinWidth}" />
        <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" />
        <Setter Property="Background" Value="{ThemeResource SystemControlBackgroundAltMediumLowBrush}" />
        <Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundBaseMediumLowBrush}" />
        <Setter Property="BorderThickness" Value="{ThemeResource ComboBoxBorderThemeThickness}" />
        <Setter Property="TabNavigation" Value="Once" />
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
        <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Disabled" />
        <Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
        <Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="True" />
        <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
        <Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="VerticalAlignment" Value="Top" />
        <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
        <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <CarouselPanel />
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ComboBox">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlPageBackgroundAltMediumBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background"
                                           Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background"
                                           Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundListMediumBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background"
                                           Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter" Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextBlock"
                                           Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DropDownGlyph"
                                           Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HighlightBackground"
                               Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <DoubleAnimation Storyboard.TargetName="HighlightBackground"
                               Storyboard.TargetProperty="Opacity"
                               To="1"
                               Duration="0" />
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                         Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextBlock"
                                           Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DropDownGlyph"
                   Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseMediumHighBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="FocusedPressed" >
                                    <Storyboard>
                                        <DoubleAnimation
                    Storyboard.TargetName="HighlightBackground"
                    Storyboard.TargetProperty="Opacity"
                    To="1"
                    Duration="0" />
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                         Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextBlock"
                                           Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DropDownGlyph"
                   Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseMediumHighBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unfocused" />
                                <VisualState x:Name="PointerFocused" />
                                <VisualState x:Name="FocusedDropDown">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames
                    Storyboard.TargetName="PopupBorder"
                    Storyboard.TargetProperty="Visibility"
                    Duration="0">
                                            <DiscreteObjectKeyFrame KeyTime="0">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Visible</Visibility>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="DropDownStates">
                                <VisualState x:Name="Opened">
                                    <Storyboard>
                                        <SplitOpenThemeAnimation
                    OpenedTargetName="PopupBorder"
                    ClosedTargetName="ContentPresenter"
                    OffsetFromCenter="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.DropDownOffset}"
                    OpenedLength="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.DropDownOpenedHeight}"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Closed">
                                    <Storyboard>
                                        <SplitCloseThemeAnimation
                    OpenedTargetName="PopupBorder"
                    ClosedTargetName="ContentPresenter"
                    OffsetFromCenter="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.DropDownOffset}"
                    OpenedLength="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.DropDownOpenedHeight}"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <ContentPresenter x:Name="HeaderContentPresenter"
            x:DeferLoadStrategy="Lazy"
            Margin="{ThemeResource ComboBoxHeaderThemeMargin}"
            FlowDirection="{TemplateBinding FlowDirection}"
            FontWeight="{ThemeResource ComboBoxHeaderThemeFontWeight}"
            Visibility="Collapsed"
            Content="{TemplateBinding Header}"
            ContentTemplate="{TemplateBinding HeaderTemplate}" />
                        <Border x:Name="Background"
            Grid.Row="1"
            Grid.ColumnSpan="2"
            Background="{TemplateBinding Background}"
            BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}" />
                        <Border x:Name="HighlightBackground"
            Grid.Row="1"
            Grid.ColumnSpan="2"
            Background="{ThemeResource SystemControlHighlightListAccentLowBrush}"
            BorderBrush="{ThemeResource SystemControlHighlightBaseMediumLowBrush}"
            BorderThickness="{TemplateBinding BorderThickness}"
            Opacity="0" />
                        <ContentPresenter x:Name="ContentPresenter"
            Grid.Row="1"
            Margin="{TemplateBinding Padding}"
            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
            VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                            <TextBlock x:Name="PlaceholderTextBlock"
              Text="{TemplateBinding PlaceholderText}"
              Foreground="{ThemeResource SystemControlPageTextBaseHighBrush}"/>
                        </ContentPresenter>
                        <Grid Grid.Row="1"
                                    Grid.Column="1"
                                    Margin="0,10,10,10">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition/>
                                <ColumnDefinition/>
                            </Grid.ColumnDefinitions>
                            <Button x:Name="ClearButton"
                                    Foreground="Black"
                                    FontFamily="{ThemeResource SymbolThemeFontFamily}"
                                    FontSize="12"
                                    Content="&#xE894;"
                                    VerticalAlignment="Center"
                                    BorderThickness="0"
                                    Background="Transparent"
                                    Height="20"
                                    Width="30"
                                    Padding="5,0"
                                    Style="{StaticResource NoHoverButtonStyle}"
                                    AutomationProperties.AccessibilityView="Raw" />
                            <FontIcon x:Name="DropDownGlyph"
                                      Grid.Column="1"
            IsHitTestVisible="False"
            Foreground="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
            FontFamily="{ThemeResource SymbolThemeFontFamily}"
            FontSize="12"
            Glyph="&#xE0E5;"
            HorizontalAlignment="Right"
            VerticalAlignment="Center"
            AutomationProperties.AccessibilityView="Raw" />
                        </Grid>
                        <Popup x:Name="Popup">
                            <Border
              x:Name="PopupBorder"
              Background="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}"
              BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
              BorderThickness="{ThemeResource ComboBoxDropdownBorderThickness}"
              Margin="0,-1,0,-1"
              HorizontalAlignment="Stretch">
                                <ScrollViewer x:Name="ScrollViewer"
                Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}"
                MinWidth="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.DropDownContentMinWidth}"
                VerticalSnapPointsType="OptionalSingle"
                VerticalSnapPointsAlignment="Near"
                HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
                HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
                IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
                IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
                IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
                BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
                ZoomMode="Disabled"
                AutomationProperties.AccessibilityView="Raw">
                                    <ItemsPresenter Margin="{ThemeResource ComboBoxDropdownContentMargin}" />
                                </ScrollViewer>
                            </Border>
                        </Popup>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

XAML Behavior for ComboBox:

public sealed class ComboBoxBehavior : DependencyObject, IBehavior
    {
        public DependencyObject AssociatedObject { get; set; }

        public bool IsNullable
        {
            get => (bool)this.GetValue(IsNullableProperty);
            set => this.SetValue(IsNullableProperty, value);
        }

        public static readonly DependencyProperty IsNullableProperty = DependencyProperty.Register(
            "IsNullable",
            typeof(bool),
            typeof(ComboBoxBehavior),
            new PropertyMetadata(false, null));

        public void Attach(DependencyObject associatedObject)
        {
            if (!(associatedObject is ComboBox cb))
            {
                throw new ArgumentException("ComboBoxBehavior can only be used with a ComboBox.");
            }

            this.AssociatedObject = associatedObject;
            if (IsNullable)
            {
                cb.Loaded += OnComboBoxLoaded;
                cb.SelectionChanged += OnSelectionChanged;
            }
        }

        private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ApplyIsNullable(sender as ComboBox);
        }

        private void OnComboBoxLoaded(object sender, RoutedEventArgs e)
        {
            ApplyIsNullable(sender as ComboBox);
        }

        private void ApplyIsNullable(ComboBox comboBox)
        {
            comboBox.ApplyTemplate();
            var clearButton = GetClearButton(comboBox);
            if (clearButton != null)
            {
                clearButton.Click -= OnClearButtonClicked;
                clearButton.Click += OnClearButtonClicked;

                if (IsNullable && comboBox.SelectedIndex != -1)
                {
                    clearButton.Visibility = Visibility.Visible;
                }
                else
                {
                    clearButton.Visibility = Visibility.Collapsed;
                }
            }
        }

        private void OnClearButtonClicked(object sender, RoutedEventArgs e)
        {
            (this.AssociatedObject as ComboBox).SelectedIndex = -1;
        }

        private Button GetClearButton(DependencyObject reference)
        {

            for (int childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(reference); childIndex++)
            {
                var child = VisualTreeHelper.GetChild(reference, childIndex);

                if (child is Button && ((Button)child).Name == "ClearButton")
                {
                    return (Button)child;
                }

                var clearButton = GetClearButton(child);
                if (clearButton is Button)
                {
                    return clearButton;
                }
            }

            return null;
        }

        public void Detach()
        {
            ComboBox comboBox = null;
            if (this.AssociatedObject is ComboBox)
            {
                comboBox = this.AssociatedObject as ComboBox;
                comboBox.Loaded -= OnComboBoxLoaded;
                comboBox.SelectionChanged -= OnSelectionChanged;
            }
            this.AssociatedObject = null;
        }
    }

How to use with ComobBox:

<ComboBox ItemsSource="{Binding Source={StaticResource ViewModel}, Path=Actors}"
                  Height="25" Width="300"
                  HorizontalAlignment="Left" VerticalAlignment="Top"
                  Style="{StaticResource ComboBoxWithClearButtonStyle}">
            <interactivity:Interaction.Behaviors>
                <behaviors:ComboBoxBehavior IsNullable="True"/>
            </interactivity:Interaction.Behaviors>
</ComboBox>
Dishant
  • 1,545
  • 12
  • 29