The new text will never be present in the items inside ComboBox. Below is the full XAML + code-behind that does not work as I wish. What I am trying to achieve is to have the user select an actual group of items from the combo box, or a No Group (italic, grayed out) item that should be applied as an empty string in the text box inside the ComboBox.
I also tried:
- with StaysOpenOnEdit="True"(with the same result) and
- by handling the Selectedevent of the"click me"ComboBoxItem(the event handler is called before theTextorSelectedItemproperties of the ComboBox change).
XAML
<Window x:Class="cs_wpf_test_12.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:cs_wpf_test_12"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel Orientation="Vertical">
        <ComboBox SelectionChanged="ComboBox_SelectionChanged"
                  IsEditable="True">
            <ComboBoxItem>test</ComboBoxItem>
            <ComboBoxItem Foreground="Gray">click me</ComboBoxItem>
        </ComboBox>
    </StackPanel>
</Window>
Code-behind
internal bool HandlingSelectionChange = false;
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (HandlingSelectionChange)
    {
        return;
    }
    HandlingSelectionChange = true;
    var cb = sender as ComboBox;
    if (cb.Text == "click me")
    {
        cb.Text = "";
        e.Handled = true;
    }
    HandlingSelectionChange = false;
}
Expected: when the user clicks on the "click me" item in the drop-down the text of the ComboBox becomes an empty string. The rest of the items, when clicked, should copy their text normally into the text box of the ComboBox.
Actual:
- Start the program.
- Select the "click me" item.
- The Text changes to "click me" (not grayed out) instead of "".
- Click on the "test" item.
- The Text changes to "" (empty string) instead of "test".
- Click again on the "test" item.
- The Text changes to "test".
Update
I wish to use MVVM but I am still a beginner. I have several ComboBoxes like shown above inside a DataGridTemplateColumn, and for each of the ComboBoxes (which should have the same drop-down contents) I think I should have a ViewModel for each of its ComboBoxItems. If possible, I would like to learn how I could I use MVVM correctly in this situation.
The big XAML
<DataGridTemplateColumn Header="Group Name">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Label Content="{Binding GroupName, Mode=OneWay}">
            </Label>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ComboBox IsEditable="True" StaysOpenOnEdit="True"
                        ItemsSource="{Binding Path=Clocks.GroupsVM,
                RelativeSource={RelativeSource AncestorType=local:ClockDataGrid}}"
                        PreviewKeyDown="ComboBox_PreviewKeyDown"
                        SelectionChanged="ComboBox_SelectionChanged"
                        Text="{Binding GroupName}">
                <ComboBox.Resources>
                    <Style TargetType="ComboBoxItem">
                        <Setter Property="FontStyle" Value="{Binding FontStyle}"/>
                        <Setter Property="Foreground" Value="{Binding Foreground}"/>
                    </Style>
                </ComboBox.Resources>
            </ComboBox>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The big code-behind
private void ComboBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    var cb = sender as ComboBox;
    if ((e.Key == Key.Return ||
        e.Key == Key.Enter) &&
        cb.Text != "")
    {
        bool duplicate = false;
        foreach (ClockGroupVM vm in Clocks.GroupsVM)
        {
            if (vm.Name == cb.Text)
            {
                cb.SelectedItem = vm;
                duplicate = true;
                break;
            }
        }
        if (duplicate)
        {
            return;
        }
        // create a ClockGroupM and corresponding ClockGroupVM
        // (ClockGroupVM inherits from ClockGroupM)
        var cvm = new ClockGroupVM()
        {
            Name = cb.Text
        };
        Clocks.Groups.Insert(0, cvm);
        cb.SelectedItem = cvm;
    }
}
internal bool HandlingSelectionChange = false;
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (HandlingSelectionChange)
    {
        return;
    }
    HandlingSelectionChange = true;
    var cb = sender as ComboBox;
    //if (cb.SelectedItem is the VM with Style != Normal)
    ClockGroupVM foundVM = null;
    foreach (ClockGroupVM vm in Clocks.GroupsVM)
    {
        if (vm.FontStyle != FontStyles.Normal &&
            ReferenceEquals(cb.SelectedItem, vm))
        {
            foundVM = vm;
            break;
        }
    }
    if (foundVM != null)
    {
        cb.Text = "";
        e.Handled = true;
    }
    HandlingSelectionChange = false;
}
 
    