Search code examples
c#wpfxamlcombobox

Toggle CheckBox within ComboBoxItem (Combobox list) without selecting the item in WPF - C# - XAML


I have a ComboBox in a WPF application that contains multiple ComboBoxItems, each hosting a CheckBox. I want users to be able to toggle the CheckBox without actually selecting the ComboBoxItem. Currently, if I click on the checkbox, it correctly checks the checkbox, but if i click on the item(and not the checkbox) it selects that item, instead I simply want to use this list to select the checkboxes, and dont want to have any items selected.

DEMO - When clicking on checkboxes:

enter image description here

DEMO - If I click on the item:

enter image description here

As you can see, when I click on the item, on the checkbox then it checks the item, but if i click on the item it then selects and displays that item. I only care about checking the items and dont want to:

  1. Have any items displayed when the dropdown is closed
  2. being able to select any items.

XAML Code:

<ComboBox Margin="40,10,0,2" Name="ComboBox1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="250" Height="30" Loaded="ComboBox1_Loaded">
                                        <!-- The items will be added programmatically -->
                                    </ComboBox>

C# Code Behind:

private void ComboBox1_Loaded(object sender, RoutedEventArgs e)
        {
            // List of items to be added to the ComboBox
            string[] items = new string[] {
                "Example1", "Example2", "Example3", "Example14", "Example5", 
            };

            foreach (string item in items)
            {
                // Create a new CheckBox
                System.Windows.Controls.CheckBox checkBox = new System.Windows.Controls.CheckBox
                {
                    Content = item,
                    Name = "chk" + item.Replace(" ", "")
                };

                // Create a new ComboBoxItem and add the CheckBox to it
                ComboBoxItem comboBoxItem = new ComboBoxItem();
                comboBoxItem.Content = checkBox;

                // Add the ComboBoxItem to the ComboBox
                ComboBox1.Items.Add(comboBoxItem);
            }
        }

        private void ComboBox1_DropDownClosed(object sender, EventArgs e)
        {
            // StringBuilder to hold all checked items
            var checkedItems = new StringBuilder();

            foreach (ComboBoxItem comboBoxItem in ComboBox1.Items)
            {
                if (comboBoxItem.Content is System.Windows.Controls.CheckBox checkBox && checkBox.IsChecked == true)
                {
                    // Add the checked item to the StringBuilder
                    checkedItems.AppendLine(checkBox.Content.ToString());
                }
            }

            // Check if we have any checked items and write them to debug output
            if (checkedItems.Length > 0)
            {
                Debug.WriteLine("Checked Items:");
                Debug.WriteLine(checkedItems.ToString());
            }
        }

I hope this is something you can help me out with.

Best,


Solution

  • If you don't need the functionality of ComboBox, other control such as Menu will suffice. Here is a sample using CommunityToolkit.Mvvm.

    using System.Collections.ObjectModel;
    using CommunityToolkit.Mvvm.ComponentModel;
    
    public partial class MainWindowViewModel : ObservableObject
    {
        public ObservableCollection<ItemViewModel> Items { get; } = new();
    
        public MainWindowViewModel()
        {
            // Populate Items.
        }
    }
    
    public partial class ItemViewModel : ObservableObject
    {
        [ObservableProperty]
        string _name;
    
        [ObservableProperty]
        bool _isSelected;
    
        public ItemViewModel(string name) => this.Name = name;
    }
    
    <Menu>
        <MenuItem Header="Transportation"
                  ItemsSource="{Binding Items}">
            <MenuItem.ItemContainerStyle>
                <Style TargetType="{x:Type MenuItem}">
                    <Setter Property="OverridesDefaultStyle" Value="True"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type MenuItem}">
                                <CheckBox Content="{Binding Name, Mode=OneTime}"
                                          IsChecked="{Binding IsSelected, Mode=TwoWay}"/>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </MenuItem.ItemContainerStyle>
        </MenuItem>
    </Menu>
    

    You can check whether each item is checked by iterating the ObservableCollection.