127

In a WPF app, in MVP app, I have a combo box,for which I display the data fetched from Database. Before the items added to the Combo box, I want to display the default text such as

" -- Select Team --"

so that on pageload it displays and on selecting it the text should be cleared and the items should be displayed.

Selecting data from DB is happening. I need to display the default text until the user selects an item from combo box.

Please guide me

stema
  • 90,351
  • 20
  • 107
  • 135
user301016
  • 2,207
  • 7
  • 36
  • 50

24 Answers24

129

The easiest way I've found to do this is:

<ComboBox Name="MyComboBox"
 IsEditable="True"
 IsReadOnly="True"
 Text="-- Select Team --" />

You'll obviously need to add your other options, but this is probably the simplest way to do it.

There is however one downside to this method which is while the text inside your combo box will not be editable, it is still selectable. However, given the poor quality and complexity of every alternative I've found to date, this is probably the best option out there.

Chris Walter
  • 2,366
  • 1
  • 18
  • 10
  • Great answer Chris! I would just add Focusable="True", but that is just cosmetic change. – Slavisa May 09 '13 at 14:33
  • 6
    perfect answer Chris. One property can do such a big difference :D – Aster Veigas Sep 08 '13 at 21:14
  • 6
    `Focusable="False" IsEditable="True" IsReadOnly="True"` – Kamil Lelonek Jan 01 '14 at 01:38
  • 1
    +1. Unfortunatelly it does not work with mixed items (for example if combobox items are images). – greenoldman Nov 17 '14 at 14:13
  • 21
    Simple and working solution. WPF controls have this kind of problems all over the framework. Here and there, controls are missing features that most developers would need. As the result, developers waste their time searching for solutions, buying third-party alternative controls, or implementing workarounds... Does the WPF team even use their controls for their own developments? – Damn Vegetables Jan 10 '15 at 18:27
  • Delightful hack. – henrykodev Aug 17 '17 at 06:05
  • Greenoldman, if you're displaying an image and possibly text, then probably you're using a datatemplate for the item template of the combobox. Perhaps you could put a style in the page's resources that is exactly like the datatemplate you're using in the combobox's itemtemplate. This style would be a default that would show when working with a new data item. – Rod Jan 10 '20 at 20:28
96

You can do this without any code behind by using a IValueConverter.

<Grid>
   <ComboBox
       x:Name="comboBox1"
       ItemsSource="{Binding MyItemSource}"  />
   <TextBlock
       Visibility="{Binding SelectedItem, ElementName=comboBox1, Converter={StaticResource NullToVisibilityConverter}}"
       IsHitTestVisible="False"
       Text="... Select Team ..." />
</Grid>

Here you have the converter class that you can re-use.

public class NullToVisibilityConverter : IValueConverter
{
    #region Implementation of IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value == null ? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

And finally, you need to declare your converter in a resource section.

<Converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />

Where Converters is the place you have placed the converter class. An example is:

xmlns:Converters="clr-namespace:MyProject.Resources.Converters"

The very nice thing about this approach is no repetition of code in your code behind.

Tri Q Tran
  • 5,500
  • 2
  • 37
  • 58
  • I would like to use this, but seems it is not allowed in the cases that the combobox is the header of a datagrid . . . XAML gives an error that the header is already defined (or perhaps cannot be defined more than once). Any ideas? I am thinking just to use a null value option, which will then allow for a reset by selecting it, but seems a little sloppy. – Paul Gibson Jan 29 '15 at 19:57
  • 1
    A big reason this is an excellent solution is because just about every data-bound WPF project makes use of a NullToVisibilityConverter so it's already there most of the time - might as well make use of it! – tpartee Jun 16 '15 at 00:36
  • 2
    Actually you can use a `DataTrigger` to avoid even the converter code here :) – Billy ONeal Sep 02 '15 at 18:17
55

I like Tri Q's answer, but those value converters are a pain to use. PaulB did it with an event handler, but that's also unnecessary. Here's a pure XAML solution:

<ContentControl Content="{Binding YourChoices}">
    <ContentControl.ContentTemplate>
        <DataTemplate>
            <Grid>
                <ComboBox x:Name="cb" ItemsSource="{Binding}"/>
                <TextBlock x:Name="tb" Text="Select Something" IsHitTestVisible="False" Visibility="Hidden"/>
            </Grid>
            <DataTemplate.Triggers>
                <Trigger SourceName="cb" Property="SelectedItem" Value="{x:Null}">
                    <Setter TargetName="tb" Property="Visibility" Value="Visible"/>
                </Trigger>
            </DataTemplate.Triggers>
        </DataTemplate>
    </ContentControl.ContentTemplate> 
</ContentControl>
CrApHeR
  • 2,595
  • 4
  • 25
  • 40
HappyNomad
  • 4,458
  • 4
  • 36
  • 55
41

No one said a pure xaml solution has to be complicated. Here's a simple one, with 1 data trigger on the text box. Margin and position as desired

<Grid>
    <ComboBox x:Name="mybox" ItemsSource="{Binding}"/>
    <TextBlock Text="Select Something" IsHitTestVisible="False">
           <TextBlock.Style>
                <Style TargetType="TextBlock">
                      <Setter Property="Visibility" Value="Hidden"/>
                      <Style.Triggers>
                            <DataTrigger Binding="{Binding ElementName=mybox,Path=SelectedItem}" Value="{x:Null}">
                                  <Setter Property="Visibility" Value="Visible"/>
                             </DataTrigger>
                      </Style.Triggers>
                </Style>
           </TextBlock.Style>
     </TextBlock>
</Grid>
JoanComasFdz
  • 2,911
  • 5
  • 34
  • 50
IceForge
  • 419
  • 4
  • 2
  • 5
    I needed to move the "Visibility="Hidden" into the data trigger. then it worked as expected. Definitely the most straigh forward approach I've seen. For reuseability, I moved the style into a resource – Mitch Aug 09 '13 at 14:50
  • @Mitch IceForce's answer isnt working for me, what did you change to get it working? – Chris Apr 30 '14 at 10:20
  • 1
    @Chris I think he meant adding `` outside the trigger (inside the style) and removing `Visibility="Hidden"` from the actual textblock element – Reinstate Monica Please May 23 '15 at 01:39
  • @Mitch, how do you move the Textblock style into a resource for reuse if you have the ElementName in the DataTrigger pointing to a specific object (mybox)? Is there any way to specify that name in a generic way? – CrApHeR Nov 18 '15 at 01:21
29

Set IsEditable="True" on the ComboBox element. This will display the Text property of the ComboBox.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
medusa
  • 291
  • 3
  • 3
18

I dont know if it's directly supported but you could overlay the combo with a label and set it to hidden if the selection isn't null.

eg.

<Grid>
   <ComboBox Text="Test" Height="23" SelectionChanged="comboBox1_SelectionChanged" Name="comboBox1" VerticalAlignment="Top" ItemsSource="{Binding Source=ABCD}"  />
   <TextBlock IsHitTestVisible="False" Margin="10,5,0,0" Name="txtSelectTeam" Foreground="Gray" Text="Select Team ..."></TextBlock>
</Grid>

Then in the selection changed handler ...

private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    txtSelectTeam.Visibility = comboBox1.SelectedItem == null ? Visibility.Visible : Visibility.Hidden;
}
PaulB
  • 23,264
  • 14
  • 56
  • 75
10

Based on IceForge's answer I prepared a reusable solution:

xaml style:

<Style x:Key="ComboBoxSelectOverlay" TargetType="TextBlock">
    <Setter Property="Grid.ZIndex" Value="10"/>
    <Setter Property="Foreground" Value="{x:Static SystemColors.GrayTextBrush}"/>
    <Setter Property="Margin" Value="6,4,10,0"/>
    <Setter Property="IsHitTestVisible" Value="False"/>
    <Setter Property="Visibility" Value="Hidden"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding}" Value="{x:Null}">
            <Setter Property="Visibility" Value="Visible"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

example of use:

<Grid>
     <ComboBox x:Name="cmb"
               ItemsSource="{Binding Teams}" 
               SelectedItem="{Binding SelectedTeam}"/>
     <TextBlock DataContext="{Binding ElementName=cmb,Path=SelectedItem}"
               Text=" -- Select Team --" 
               Style="{StaticResource ComboBoxSelectOverlay}"/>
</Grid>
Community
  • 1
  • 1
too
  • 3,009
  • 4
  • 37
  • 51
  • Nice. I have exteded it by binding the TextBlock's DataContext using a relative source in order to avoid having to set the name. See the next comment for Markup (code in SO's comments looks ugly) – Sascha Oct 14 '16 at 10:18
4

Not tried it with combo boxes but this has worked for me with other controls...

ageektrapped blogpost

He uses the adorner layer here to display a watermark.

Nathan Hillyer
  • 1,959
  • 1
  • 18
  • 22
Crippeoblade
  • 4,035
  • 4
  • 32
  • 28
  • Just downloaded and tried this code. It seems to work as advertised. Allows you to decorate your combo with a simple attached property containing your watermark. It also works for other controls as well. It's a much better approach than any of the other answers to this question. – Ian Oakes Aug 26 '11 at 10:20
  • Good stuff, not only it solves the ComboBox problem, but now I can get rid of the WPF Tools assembly and just use this on my TextBoxes instead of the WatermarkedTextBox control too, so full of win :) - oh btw it's A Geek Trapped not Agreed Trap! – dain Jan 05 '12 at 13:19
3

HappyNomad's solution was very good and helped me eventually arrive at this slightly different solution.

<ComboBox x:Name="ComboBoxUploadProject" 
    Grid.Row="2"
    Width="200" 
    Height="23"                           
    Margin="64,0,0,0"
    ItemsSource="{Binding projectList}"
    SelectedValue ="{Binding projectSelect}" 
    DisplayMemberPath="projectName"
    SelectedValuePath="projectId"
    >
    <ComboBox.Template>
        <ControlTemplate TargetType="ComboBox">
            <Grid>
                <ComboBox x:Name="cb" 
                    DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" 
                    ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource TemplatedParent}}"
                    SelectedValue ="{Binding SelectedValue, RelativeSource={RelativeSource TemplatedParent}}" 
                    DisplayMemberPath="projectName"
                    SelectedValuePath="projectId"
                    />
                <TextBlock x:Name="tb" Text="Select Item..." Margin="3,3,0,0" IsHitTestVisible="False" Visibility="Hidden"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger SourceName="cb" Property="SelectedItem" Value="{x:Null}">
                    <Setter TargetName="tb" Property="Visibility" Value="Visible"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </ComboBox.Template>
</ComboBox>
Nick Falco
  • 207
  • 2
  • 10
2

Easiest way is to use CompositeCollection to merge default text and data from database directly in ComboBox e.g.

    <ComboBox x:Name="SelectTeamComboBox" SelectedIndex="0">
        <ComboBox.ItemsSource>
            <CompositeCollection>
                <ComboBoxItem Visibility="Collapsed">-- Select Team --</ComboBoxItem>
                <CollectionContainer Collection="{Binding Source={StaticResource ResourceKey=MyComboOptions}}"/>
            </CompositeCollection>
        </ComboBox.ItemsSource>
    </ComboBox>

And in Resources define StaticResource to bind ComboBox options to your DataContext, because direct binding in CollectionContainer doesn't work correctly.

<Window.Resources>
    <CollectionViewSource Source="{Binding}" x:Key="MyComboOptions" />
</Window.Resources>

This way you can define your ComboBox options only in xaml e.g.

   <ComboBox x:Name="SelectTeamComboBox" SelectedIndex="0">
        <ComboBox.ItemsSource>
            <CompositeCollection>
                <ComboBoxItem Visibility="Collapsed">-- Select Team --</ComboBoxItem>
                <ComboBoxItem >Option 1</ComboBoxItem>
                <ComboBoxItem >Option 2</ComboBoxItem>
            </CompositeCollection>
        </ComboBox.ItemsSource>
    </ComboBox>
Zap
  • 21
  • 1
1

I would recommend the following:

Define a behavior

public static class ComboBoxBehaviors
{
    public static readonly DependencyProperty DefaultTextProperty =
        DependencyProperty.RegisterAttached("DefaultText", typeof(String), typeof(ComboBox), new PropertyMetadata(null));

    public static String GetDefaultText(DependencyObject obj)
    {
        return (String)obj.GetValue(DefaultTextProperty);
    }

    public static void SetDefaultText(DependencyObject obj, String value)
    {
        var combo = (ComboBox)obj;

        RefreshDefaultText(combo, value);

        combo.SelectionChanged += (sender, _) => RefreshDefaultText((ComboBox)sender, GetDefaultText((ComboBox)sender));

        obj.SetValue(DefaultTextProperty, value);
    }

    static void RefreshDefaultText(ComboBox combo, string text)
    {
        // if item is selected and DefaultText is set
        if (combo.SelectedIndex == -1 && !String.IsNullOrEmpty(text))
        {
            // Show DefaultText
            var visual = new TextBlock()
            {
                FontStyle = FontStyles.Italic,
                Text = text,
                Foreground = Brushes.Gray
            };

            combo.Background = new VisualBrush(visual)
            {
                Stretch = Stretch.None,
                AlignmentX = AlignmentX.Left,
                AlignmentY = AlignmentY.Center,
                Transform = new TranslateTransform(3, 0)
            };
        }
        else
        {
            // Hide DefaultText
            combo.Background = null;
        }
    }
}

User the behavior

<ComboBox Name="cmb" Margin="72,121,0,0" VerticalAlignment="Top"
          local:ComboBoxBehaviors.DefaultText="-- Select Team --"/>
Usman Zafar
  • 1,919
  • 1
  • 15
  • 11
  • This works like a charm for a single combo box. But when I use it with more than 1 combo, it gives me an error (but compiles and runs well) "'DefaultText' Property already registered by 'ComboBox'". [I have mentioned the fix in my blog.](http://contractnamespace.blogspot.com/2014/04/default-text-on-wpf-combo-boxes.html) – Romesh D. Niriella Apr 24 '14 at 09:30
  • Thanks for pointing this out. I could not produce this error on my computer. However, I agree typeof(ComboBoxBehaviors) should be passed in the 3rd parameter of RegisterAttached instead of typeof(ComboBox). – Usman Zafar Jun 09 '14 at 16:50
  • Although this post is a bit old, I don't see how it can work. The combo's bg is set via triggers w/multiple conditions. Try placing a combo alone on a grid and manually setting bg to 'red'. It has no effect on the area where you want a watermark to appear. It may only affect the bg behind the dropdown panel. A better solution is to copy the combobox's control template and add a few triggers and styles to paint a visual brush consisting of a textblock into the border's background. – Newclique Oct 13 '16 at 18:27
1

IceForge's answer was pretty close, and is AFAIK the easiest solution to this problem. But it missed something, as it wasn't working (at least for me, it never actually displays the text).

In the end, you can't just set the "Visibility" property of the TextBlock to "Hidden" in order for it to be hidden when the combo box's selected item isn't null; you have to SET it that way by default (since you can't check not null in triggers, by using a Setter in XAML at the same place as the Triggers.

Here's the actual solution based on his, the missing Setter being placed just before the Triggers:

<ComboBox x:Name="combo"/>
<TextBlock Text="--Select Team--" IsHitTestVisible="False">
    <TextBlock.Style>
        <Style TargetType="TextBlock">

            <Style.Setters>
                <Setter Property="Visibility" Value="Hidden"/>
            </Style.Setters>

            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=combo,Path=SelectedItem}" Value="{x:Null}">
                    <Setter Property="Visibility" Value="Visible"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBlock.Style>
</TextBlock>
Community
  • 1
  • 1
Kilazur
  • 3,089
  • 1
  • 22
  • 48
0

Not best practice..but works fine...

<ComboBox GotFocus="Focused"  x:Name="combobox1" HorizontalAlignment="Left" Margin="8,29,0,0" VerticalAlignment="Top" Width="128" Height="117"/>

Code behind

public partial class MainWindow : Window
{
    bool clearonce = true;
    bool fillonce = true;
    public MainWindow()
    {
        this.InitializeComponent();          
        combobox1.Items.Insert(0, " -- Select Team --");
        combobox1.SelectedIndex = 0;
    }

    private void Focused(object sender, RoutedEventArgs e)
    {
            if(clearonce)
            {
                combobox1.Items.Clear();
                clearonce = false;
            }
            if (fillonce)
            {
              //fill the combobox items here 
                for (int i = 0; i < 10; i++)
                {
                    combobox1.Items.Insert(i, i);
                }
                fillonce = false;
            }           
    }
}
Madi D.
  • 1,980
  • 5
  • 23
  • 44
0

I believe a watermark as mentioned in this post would work well in this case

There's a bit of code needed but you can reuse it for any combobox or textbox (and even passwordboxes) so I prefer this way

Community
  • 1
  • 1
FearlessHyena
  • 3,527
  • 33
  • 39
0

I am using an IsNullConverter class in my project and it worked for me. here is the code for it in c#,create a folder named Converter and add this class in that folder,as the trigger used doesnt supports value for rather than null,and IsNullConverter just do that

 public class IsNullConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (value == null);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
    }
}

add the namespace in xaml file like this.

xmlns:Converters="clr-namespace:TymeSheet.Converter"

means

xmlns:Converters="clr-namespace:YourProjectName.Converter"

use this line below the resources to make it availabe through xaml code

<Converters:IsNullConverter x:Key="isNullConverter" />

here is the xaml code,i used here the trigger so whenever an item is selected in the combobox the visibilty of your text becomes false.

<TextBlock Text="Select Project" IsHitTestVisible="False" FontFamily="/TimeSheet;component/Resources/#Open Sans" FontSize="14" Canvas.Right="191" Canvas.Top="22">
                        <TextBlock.Resources>
                            <Converters:IsNullConverter x:Key="isNullConverter"/>
                        </TextBlock.Resources>
                        <TextBlock.Style>
                            <Style TargetType="TextBlock">
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding ElementName=ProjectComboBox,Path=SelectedItem,Converter={StaticResource isNullConverter}}" Value="False">
                                        <Setter Property="Visibility" Value="Hidden"/>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </TextBlock.Style>
                    </TextBlock>
Safwan
  • 171
  • 1
  • 17
0

//XAML Code

// ViewModel code

    private CategoryModel _SelectedCategory;
    public CategoryModel SelectedCategory
    {
        get { return _SelectedCategory; }
        set
        {
            _SelectedCategory = value;
            OnPropertyChanged("SelectedCategory");
        }
    }

    private ObservableCollection<CategoryModel> _Categories;
    public ObservableCollection<CategoryModel> Categories
    {
        get { return _Categories; }
        set
        {
            _Categories = value;
            _Categories.Insert(0, new CategoryModel()
            {
                CategoryId = 0,
                CategoryName = " -- Select Category -- "
            });
            SelectedCategory = _Categories[0];
            OnPropertyChanged("Categories");

        }
    }
0

A little late but..

A more simple way would be to add a dummy data item to the list with parameter IsDummy=true and make sure it is not HitTestVisable and its hight is 1 pixel (using a Converter) so it wont be seen.

Than just register to SelectionChanged and in it, set the index to the dummy item index.

It works like a charm and this way you don't mess with the style and colors of the ComboBox or your application theme.

Eibi
  • 402
  • 4
  • 17
0
InitializeComponent()
yourcombobox.text=" -- Select Team --";

The above code demonstrates the simplest way to achieve it. After window load, declare the text of the combobox, using the .Text property of the combobox. This can be extended to the DatePicker, Textbox and other controls as well.

Ketan Dubey
  • 430
  • 8
  • 19
0

EDIT: Per comments below, this is not a solution. Not sure how I had it working, and can't check that project.

It's time to update this answer for the latest XAML.

Finding this SO question searching for a solution to this question, I then found that the updated XAML spec has a simple solution.

An attribute called "Placeholder" is now available to accomplish this task. It is as simple as this (in Visual Studio 2015):

<ComboBox x:Name="Selection" PlaceholderText="Select...">
    <x:String>Item 1</x:String>
    <x:String>Item 2</x:String>
    <x:String>Item 3</x:String>
</ComboBox>
Robb Sadler
  • 705
  • 10
  • 22
  • I used this solution - does the negative voter care to elaborate? Granted I am not a XAML expert, but it worked. – Robb Sadler Oct 26 '17 at 17:30
  • 1
    Although I am not the down voter, I imagine that you were down voted because there is no `PlaceholderText` property in the [`System.Windows.ComboBox` class](https://stackoverflow.com/questions/19393774/how-to-make-all-controls-resize-accordingly-proportionally-when-window-is-maximi/19398470?noredirect=1#comment82731538_19398470). This is a question about WPF, not WinForms. – Sheridan Dec 19 '17 at 09:05
  • Man this is weird - I know I was working on a XAML app, and I know I had just discovered this and saw it work. Maybe an extension was included in the project? IDK - I have since looked and for sure there is no Placeholder in ComboBox. I can't get back to the project I was working on - old client. ugh. – Robb Sadler Mar 29 '18 at 13:47
  • 2
    You are not wrong, but that's not for WPF. UWP ComboBox has this, please see this page: https://msdn.microsoft.com/en-us/library/windows/apps/mt299116.aspx?f=255&MSPPError=-2147217396 – laishiekai Mar 15 '19 at 21:36
0

I did it before binding the combobox with data from database in codebehind like this -

Combobox.Items.Add("-- Select Team --");
Combobox.SelectedIndex = 0;
Atiq Baqi
  • 612
  • 1
  • 7
  • 16
0
  1. Put a label on top of the combobox.

  2. Bind the content of the label to to the combobox Text property.

  3. Set the opacity of the combobox to zero , Opacity=0.

  4. Write default text in the combobox Text property

          <ComboBox Name="cb"
            Text="--Select Team--" Opacity="0" 
            Height="40" Width="140" >
             <ComboBoxItem Content="Manchester United" />
             <ComboBoxItem Content="Lester" />
         </ComboBox>
     </Grid>
    
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Yinon Dotan
  • 137
  • 1
  • 12
0

This is old, but here's my idea in kind of MVVM style. I'm using Stylet MVVM framework. This is View:

<UserControl x:Class="ComboBoxWithPlaceholderTextView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:s="https://github.com/canton7/Stylet"
         mc:Ignorable="d"
         >
<Grid>
    <ComboBox
                ItemsSource="{Binding ItemsSource}"
                SelectedItem="{Binding SelectedItem}"
                DropDownOpened="{s:Action DropDownOpened}"
                DropDownClosed="{s:Action DropDownClosed}"
                IsDropDownOpen="{Binding IsDropDownOpened}"
                />

</Grid>

and then in ViewModel

public class ComboBoxWithPlaceholderTextViewModel : Screen
{
    private List<string> _itemsSource;
    private string _placeholderText;
    private string _selectedItem;
    private bool _isDropDownOpened;

    public bool IsDropDownOpened
    {
        get => _isDropDownOpened;
        set
        {
            if (value == _isDropDownOpened)
            {
                return;
            }
            SetAndNotify(ref _isDropDownOpened, value);
        }
    }

    public string SelectedItem
    {
        get
        {
            return _selectedItem;
        }

        set
        {
            SetAndNotify(ref _selectedItem, value);
        }
    }

    public string PlaceholderText
    {
        get { return _placeholderText; }
        set 
        {
            if (value == _placeholderText)
            {
                return;
            }
            SetAndNotify(ref _placeholderText, value);
        }
    }

    public List<string> ItemsSource
    {
        get { return _itemsSource; }
        set 
        { 
            SetAndNotify(ref _itemsSource, value);
            if (!IsDropDownOpened && (string.IsNullOrEmpty(SelectedItem) || !SelectedItem.Equals(PlaceholderText)))
            {
                ItemsSource.Insert(0, PlaceholderText);
                SelectedItem = ItemsSource[0];
            }
        }
    }

    public void DropDownOpened()
    {
         ItemsSource.RemoveAt(0);
        SelectedItem = null;
    }

    public void DropDownClosed()
    {
        if (SelectedItem is null)
        {
            ItemsSource.Insert(0, PlaceholderText);
            SelectedItem = ItemsSource[0];
        }
    }
}

In this way I don't have to care if text will escape combo, but I have to care if placeholder text is selected.

-2

Only set the IsEditable attribute to true

<ComboBox Name="comboBox1"            
          Text="--Select Team--"
          IsEditable="true"  <---- that's all!
          IsReadOnly="true"/>
Xsan
  • 17
  • 1
-3

I know this is semi old but what about this way:

<DataTemplate x:Key="italComboWM">
    <TextBlock FontSize="11" FontFamily="Segoe UI" FontStyle="Italic" Text="--Select an item--" />
</DataTemplate>

<ComboBox EmptySelectionBoxTemplate="{StaticResource italComboWM}" />