New to Telerik UI for Xamarin? Download free 30-day trial

ComboBox with CheckBox

The following article will show you how to display checkbox for each item inside the ComboBox drop down, select item using the CheckBox control and visualize header inside the drop down part with Select All functionality.

ComboBox Selection with CheckBox

Example

Here are the steps needed to achieve the functionality describe above.

The ComboBox definition in XAML:

<telerikInput:RadComboBox Grid.Row="1"
                          BackgroundColor="White"
                          ItemsSource="{Binding Items}"
                          SelectedItems="{Binding SelectedItems}"
                          IsDropDownClosedOnSelection="False"
                          SelectionMode="Multiple"
                          DisplayMemberPath="Name"
                          ItemTemplate="{StaticResource ComboBoxItemTemplate}"
                          SelectedItemTemplate="{StaticResource ComboBoxSelectedItemTemplate}"
                          HeaderTemplate="{StaticResource ComboBoxHeaderTemplate}"
                          Margin="10, 0, 10, 0">
    <telerikInput:RadComboBox.BindingContext>
        <local:ViewModel/>
    </telerikInput:RadComboBox.BindingContext>
    <telerikInput:RadComboBox.DropDownHeight>
        <OnPlatform x:TypeArguments="x:Double">
            <On Platform="iOS">238</On>
            <On Platform="UWP">244</On>
            <On Platform="Android">248</On>
        </OnPlatform>
    </telerikInput:RadComboBox.DropDownHeight>
</telerikInput:RadComboBox>

Lets define the CheckBox control inside the ComboBox ItemTemplate:

<DataTemplate x:Key="ComboBoxItemTemplate">
    <telerikPrimitives:RadBorder>
        <telerikPrimitives:RadBorder.MinimumHeightRequest>
            <OnPlatform x:TypeArguments="x:Double">
                <On Platform="iOS" Value="44"/>
                <On Platform="Android" Value="48"/>
                <On Platform="UWP" Value="32"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.MinimumHeightRequest>
        <telerikPrimitives:RadBorder.BorderColor>
            <OnPlatform x:TypeArguments="Color" Default="#ECECEC">
                <On Platform="UWP" Value="Transparent"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.BorderColor>
        <telerikPrimitives:RadBorder.BorderThickness>
            <OnPlatform x:TypeArguments="Thickness" Default="0, 0, 0, 1">
                <On Platform="UWP" Value="0"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.BorderThickness>
        <StackLayout Orientation="Horizontal">
            <StackLayout.Padding>
                <OnPlatform x:TypeArguments="Thickness" Default="11, 12, 0, 12">
                    <On Platform="UWP" Value="6, 6, 0, 6"/>
                    <On Platform="Android" Value="11, 6, 0, 6"/>
                </OnPlatform>
            </StackLayout.Padding>
            <telerikPrimitives:RadCheckBox Margin="0, 0, 6, 0"
                                               CheckedColor="#0E88F2"
                                               IndeterminateColor="#0E88F2"
                                               InputTransparent="True"
                                               IsChecked="False"
                                               VerticalOptions="Center">
                <telerikPrimitives:RadCheckBox.Margin>
                    <OnPlatform x:TypeArguments="Thickness">
                        <On Platform="iOS" Value="3, 0, 0, 0"/>
                        <On Platform="Android" Value="8, 0, 0, 0"/>
                        <On Platform="UWP" Value="10, 0, 0, 0"/>
                    </OnPlatform>
                </telerikPrimitives:RadCheckBox.Margin>
            </telerikPrimitives:RadCheckBox>
            <Label Text="{Binding Name}"
                       VerticalTextAlignment="Center"
                       TextColor="#8A000000"
                       FontSize="14">
                <Label.Padding>
                    <OnPlatform x:TypeArguments="Thickness">
                        <On Platform="iOS" Value="3, 0, 0, 0"/>
                        <On Platform="Android" Value="8, 13, 0, 13"/>
                        <On Platform="UWP" Value="10, 6, 0, 6"/>
                    </OnPlatform>
                </Label.Padding>
            </Label>
        </StackLayout>
    </telerikPrimitives:RadBorder>
</DataTemplate>

and in SelectedItemTemplate:

<DataTemplate x:Key="ComboBoxSelectedItemTemplate">
    <telerikPrimitives:RadBorder>
        <telerikPrimitives:RadBorder.MinimumHeightRequest>
            <OnPlatform x:TypeArguments="x:Double">
                <On Platform="iOS" Value="44"/>
                <On Platform="Android" Value="48"/>
                <On Platform="UWP" Value="32"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.MinimumHeightRequest>
        <telerikPrimitives:RadBorder.BorderColor>
            <OnPlatform x:TypeArguments="Color" Default="#ECECEC">
                <On Platform="UWP" Value="Transparent"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.BorderColor>
        <telerikPrimitives:RadBorder.BackgroundColor>
            <OnPlatform x:TypeArguments="Color" Default="#F8F8F8">
                <On Platform="UWP" Value="Accent"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.BackgroundColor>
        <telerikPrimitives:RadBorder.BorderThickness>
            <OnPlatform x:TypeArguments="Thickness" Default="0, 0, 0, 1">
                <On Platform="UWP" Value="0"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.BorderThickness>
        <StackLayout Orientation="Horizontal"
                         BackgroundColor="#F8F8F8">
            <StackLayout.Padding>
                <OnPlatform x:TypeArguments="Thickness" Default="11, 12, 0, 12">
                    <On Platform="UWP" Value="6, 6, 0, 6"/>
                    <On Platform="Android" Value="11, 6, 0, 6"/>
                </OnPlatform>
            </StackLayout.Padding>
            <telerikPrimitives:RadCheckBox Margin="0, 0, 6, 0"
                                               CheckedColor="#0E88F2"
                                               IndeterminateColor="#0E88F2"
                                               InputTransparent="True"
                                               IsChecked="True"
                                               VerticalOptions="Center">
                <telerikPrimitives:RadCheckBox.Margin>
                    <OnPlatform x:TypeArguments="Thickness">
                        <On Platform="iOS" Value="3, 0, 0, 0"/>
                        <On Platform="Android" Value="8, 0, 0, 0"/>
                        <On Platform="UWP" Value="10, 0, 0, 0"/>
                    </OnPlatform>
                </telerikPrimitives:RadCheckBox.Margin>
            </telerikPrimitives:RadCheckBox>
            <Label Text="{Binding Name}"
                       VerticalTextAlignment="Center"
                       TextColor="#8A000000"
                       FontSize="14">
                <Label.Padding>
                    <OnPlatform x:TypeArguments="Thickness">
                        <On Platform="iOS" Value="3, 0, 0, 0"/>
                        <On Platform="Android" Value="8, 13, 0, 13"/>
                        <On Platform="UWP" Value="10, 6, 0, 6"/>
                    </OnPlatform>
                </Label.Padding>
            </Label>
        </StackLayout>
    </telerikPrimitives:RadBorder>
</DataTemplate>

Then lets add a checkbox inside the Drop Down HeaderTemplate. In this way we can select/unselect all items from the drop down list.

<DataTemplate x:Key="ComboBoxHeaderTemplate">
    <telerikPrimitives:RadBorder>
        <telerikPrimitives:RadBorder.MinimumHeightRequest>
            <OnPlatform x:TypeArguments="x:Double">
                <On Platform="iOS" Value="44"/>
                <On Platform="Android" Value="48"/>
                <On Platform="UWP" Value="32"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.MinimumHeightRequest>
        <telerikPrimitives:RadBorder.BorderColor>
            <OnPlatform x:TypeArguments="Color" Default="#ECECEC">
                <On Platform="UWP" Value="Transparent"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.BorderColor>
        <telerikPrimitives:RadBorder.BorderThickness>
            <OnPlatform x:TypeArguments="Thickness" Default="0, 0, 0, 1">
                <On Platform="UWP" Value="0"/>
            </OnPlatform>
        </telerikPrimitives:RadBorder.BorderThickness>
        <StackLayout Orientation="Horizontal"
                         BackgroundColor="#DADADA">
            <StackLayout.Padding>
                <OnPlatform x:TypeArguments="Thickness" Default="11, 12, 0, 12">
                    <On Platform="UWP" Value="6, 6, 0, 6"/>
                    <On Platform="Android" Value="11, 6, 0, 6"/>
                </OnPlatform>
            </StackLayout.Padding>
            <telerikPrimitives:RadCheckBox IsChecked="{Binding SelectAllChecked}"
                                               CheckedColor="#0E88F2"
                                               IndeterminateColor="#0E88F2"
                                               InputTransparent="True"
                                               VerticalOptions="Center">
                <telerikPrimitives:RadCheckBox.Margin>
                    <OnPlatform x:TypeArguments="Thickness">
                        <On Platform="iOS" Value="3, 0, 0, 0"/>
                        <On Platform="Android" Value="8, 0, 0, 0"/>
                        <On Platform="UWP" Value="10, 0, 0, 0"/>
                    </OnPlatform>
                </telerikPrimitives:RadCheckBox.Margin>
            </telerikPrimitives:RadCheckBox>
            <Label Text="Select All Cities" 
                       TextColor="Black"
                       FontAttributes="Bold"
                       VerticalTextAlignment="Center">
                <Label.Padding>
                    <OnPlatform x:TypeArguments="Thickness">
                        <On Platform="iOS" Value="3, 0, 0, 0"/>
                        <On Platform="Android" Value="8, 13, 0, 13"/>
                        <On Platform="UWP" Value="10, 6, 0, 6"/>
                    </OnPlatform>
                </Label.Padding>
            </Label>
            <StackLayout.GestureRecognizers>
                <TapGestureRecognizer Command="{Binding SelectAllCommand}"/>
            </StackLayout.GestureRecognizers>
        </StackLayout>
    </telerikPrimitives:RadBorder>
</DataTemplate>

the business model used:

public class City
{
    public string Name { get; set; }
    public int Population { get; set; }
}

In addition, there is a logic inside the ViewModel whether the selection is made internally of from the UI - SelectAll option.

Here is the ViewModel used:

public class ViewModel : NotifyPropertyChangedBase
{
    private ObservableCollection<object> selectedItems;
    private bool? selectAllChecked = false;
    private bool isInternalCheckChanged;

    public ViewModel()
    {
        this.Items = new ObservableCollection<City>
        {
            new City { Name = "Tokyo", Population = 13929286 },
            new City { Name = "New York", Population = 8623000 },
            new City { Name = "London", Population = 8908081 },
            new City { Name = "Madrid", Population = 3223334 },
            new City { Name = "Los Angeles", Population = 4000000},
            new City { Name = "Paris", Population = 2141000 },
            new City { Name = "Beijing", Population = 21540000 },
            new City { Name = "Singapore", Population = 5612000 },
            new City { Name = "New Delhi", Population = 18980000 },
            new City { Name = "Bangkok", Population = 8305218 },
            new City { Name = "Berlin", Population = 3748000 },
        };

        this.SelectAllCommand = new Command(this.OnSelectAllCommandExecute);
    }

    public ObservableCollection<City> Items { get; set; }
    public ICommand SelectAllCommand { get; set; }

    public ObservableCollection<object> SelectedItems
    {
        get
        {
            return this.selectedItems;
        }
        set
        {
            if (this.selectedItems != value)
            {
                if (this.selectedItems != null)
                {
                    this.selectedItems.CollectionChanged -= this.OnSelectedItemsCollectionChanged;
                }

                this.selectedItems = value;

                if (this.selectedItems != null)
                {
                    this.selectedItems.CollectionChanged += this.OnSelectedItemsCollectionChanged;
                }

                this.OnPropertyChanged();
            }
        }
    }

    public bool? SelectAllChecked
    {
        get
        {
            return this.selectAllChecked;
        }
        set
        {
            if (this.selectAllChecked != value)
            {
                this.selectAllChecked = value;

                if (!this.isInternalCheckChanged && this.selectAllChecked.HasValue)
                {
                    if (this.selectAllChecked.Value)
                    {
                        foreach (var store in this.Items)
                        {
                            if (!this.SelectedItems.Contains(store))
                            {
                                this.SelectedItems.Add(store);
                            }
                        }
                    }
                    else
                    {
                        this.SelectedItems.Clear();
                    }
                }

                this.OnPropertyChanged();
            }
        }
    }

    private void OnSelectAllCommandExecute(object obj)
    {
        if (this.selectAllChecked == null)
        {
            this.SelectAllChecked = false;
        }
        else
        {
            this.SelectAllChecked = !this.selectAllChecked;
        }
    }

    private void OnSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        var action = e.Action;
        if (action == NotifyCollectionChangedAction.Add)
        {
            this.isInternalCheckChanged = true;
            if (this.SelectedItems.Count == this.Items.Count)
            {
                this.SelectAllChecked = true;
            }
            else
            {
                this.SelectAllChecked = null;
            }
            this.isInternalCheckChanged = false;

            return;
        }

        if (action == NotifyCollectionChangedAction.Remove)
        {
            this.isInternalCheckChanged = true;
            if (this.SelectedItems.Count == 0)
            {
                this.SelectAllChecked = false;
            }
            else
            {
                this.SelectAllChecked = null;
            }
            this.isInternalCheckChanged = false;
        }
    }
}

This is the result:

ComboBox Selection with CheckBox

Example for ComboBox with CheckBox selection can be found in the ComboBox/How To section from the SDK Browser Application.

See Also

In this article