如何在WPF的pageload上的组合框中显示默认文本“—选择Team—”?

时间:2023-01-28 12:25:19

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

在WPF应用程序中,在MVP应用程序中,我有一个组合框,用于显示从数据库中获取的数据。在将项目添加到组合框之前,我想显示默认文本,例如

" -- Select Team --"

“——选择团队——”

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

所以在pageload上它会显示,在选择它时文本应该被清除,条目应该被显示。

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

正在从DB中选择数据。我需要显示默认文本,直到用户从组合框中选择一个项目。

Please guide me

请指导我

22 个解决方案

#1


85  

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

通过使用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.

这种方法的好处是不会在代码后面重复代码。

#2


85  

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.

不过,这个方法也有一个缺点,即虽然组合框中的文本不可编辑,但仍然可以选择。然而,鉴于到目前为止我发现的每一种选择的质量和复杂性,这可能是最好的选择。

#3


46  

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:

我喜欢Tri Q的答案,但是这些值转换器很难使用。PaulB用事件处理程序完成的,但是这也是不必要的。这里有一个纯XAML解决方案:

<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>

#4


29  

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

没有人说单纯的xaml解决方案必须是复杂的。这里有一个简单的例子,文本框中有一个数据触发器。根据需要的裕度和位置

<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>

#5


18  

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

在组合框元素上设置IsEditable=True。这将显示Combobox的文本属性

#6


14  

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.

我不知道它是否被直接支持,但是你可以用一个标签覆盖这个组合,如果选择不是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;
}

#7


4  

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

我没有尝试过组合框,但这对我的其他控件很有效……

ageektrapped blogpost

ageektrapped博客

He uses the adorner layer here to display a watermark.

他在这里使用装饰层来显示水印。

#8


4  

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

基于IceForge的回答,我准备了一个可重用的解决方案:

xaml style:

xaml风格:

<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>

#9


3  

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

HappyNomad的解决方案非常好,最终帮助我找到了这个稍微不同的解决方案。

<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>

#10


2  

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

最简单的方法是使用CompositeCollection直接在ComboBox中合并来自数据库的默认文本和数据。

    <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.

在资源中定义StaticResource将ComboBox选项绑定到您的DataContext,因为在CollectionContainer中直接绑定不能正常工作。

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

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

这样你可以只在xaml中定义你的ComboBox选项。

   <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>

#11


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 --"/>

#12


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).

IceForge的答案非常接近,并且是这个问题最简单的解决方案。但它漏掉了一些东西,因为它不起作用(至少对我来说,它从来没有显示过文本)。

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.

最后,您不能仅仅将TextBlock的“可见性”属性设置为“Hidden”,以便在组合框的选定项不是null时将其隐藏;您必须在默认情况下设置它(因为在触发器中不能检查非null,在XAML中使用Setter和触发器一样)。

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

这是基于his的实际解决方案,丢失的Setter就放在触发器之前:

<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>

#13


1  

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.

是时候为最新的XAML更新这个答案了。

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

在寻找这个问题的解决方案时,我发现更新后的XAML规范有一个简单的解决方案。

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

现在可以使用名为“占位符”的属性来完成此任务。就这么简单(在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>

#14


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;
            }           
    }
}

#15


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

需要一些代码,但是您可以将它用于任何组合框或文本框(甚至是密码框),所以我更喜欢这种方式

#16


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

我正在我的项目中使用一个IsNullConverter类,它对我很有用。这里是c#中的代码,创建一个名为Converter的文件夹,并在该文件夹中添加这个类,因为使用的触发器不支持value而不是null, IsNullConverter只支持这个操作

 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.

在xaml文件中添加命名空间如下所示。

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

使用参考资料下面的这一行代码通过xaml代码可用

<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.

这是xaml代码,我在这里使用了触发器,所以每当在combobox中选择一个项目时,文本的可见性就会变为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>

#17


0  

//XAML Code

/ / XAML代码

// 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");

        }
    }

#18


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.

一种更简单的方法是将一个假数据项添加到参数is哑=true的列表中,并确保它不是HitTestVisable,并且它的高度为1像素(使用转换器),因此不会被看到。

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

不只是注册到SelectionChanged中,将索引设置为哑项索引。

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

它的工作方式就像一种魅力,这样你就不会打乱ComboBox的风格和颜色,或者你的应用主题。

#19


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.

上面的代码演示了实现它的最简单方法。在窗口加载后,使用combobox的. text属性声明combobox的文本。这也可以扩展到DatePicker、Textbox和其他控件。

#20


0  

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

在将combobox与数据库中的数据绑定在一起之前,我这样做了。

Combobox.Items.Add("-- Select Team --");
Combobox.SelectedIndex = 0;

#21


-2  

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}" />

#22


-3  

Only set the IsEditable attribute to true

只将IsEditable属性设置为true

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

#1


85  

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

通过使用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.

这种方法的好处是不会在代码后面重复代码。

#2


85  

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.

不过,这个方法也有一个缺点,即虽然组合框中的文本不可编辑,但仍然可以选择。然而,鉴于到目前为止我发现的每一种选择的质量和复杂性,这可能是最好的选择。

#3


46  

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:

我喜欢Tri Q的答案,但是这些值转换器很难使用。PaulB用事件处理程序完成的,但是这也是不必要的。这里有一个纯XAML解决方案:

<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>

#4


29  

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

没有人说单纯的xaml解决方案必须是复杂的。这里有一个简单的例子,文本框中有一个数据触发器。根据需要的裕度和位置

<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>

#5


18  

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

在组合框元素上设置IsEditable=True。这将显示Combobox的文本属性

#6


14  

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.

我不知道它是否被直接支持,但是你可以用一个标签覆盖这个组合,如果选择不是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;
}

#7


4  

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

我没有尝试过组合框,但这对我的其他控件很有效……

ageektrapped blogpost

ageektrapped博客

He uses the adorner layer here to display a watermark.

他在这里使用装饰层来显示水印。

#8


4  

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

基于IceForge的回答,我准备了一个可重用的解决方案:

xaml style:

xaml风格:

<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>

#9


3  

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

HappyNomad的解决方案非常好,最终帮助我找到了这个稍微不同的解决方案。

<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>

#10


2  

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

最简单的方法是使用CompositeCollection直接在ComboBox中合并来自数据库的默认文本和数据。

    <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.

在资源中定义StaticResource将ComboBox选项绑定到您的DataContext,因为在CollectionContainer中直接绑定不能正常工作。

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

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

这样你可以只在xaml中定义你的ComboBox选项。

   <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>

#11


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 --"/>

#12


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).

IceForge的答案非常接近,并且是这个问题最简单的解决方案。但它漏掉了一些东西,因为它不起作用(至少对我来说,它从来没有显示过文本)。

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.

最后,您不能仅仅将TextBlock的“可见性”属性设置为“Hidden”,以便在组合框的选定项不是null时将其隐藏;您必须在默认情况下设置它(因为在触发器中不能检查非null,在XAML中使用Setter和触发器一样)。

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

这是基于his的实际解决方案,丢失的Setter就放在触发器之前:

<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>

#13


1  

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.

是时候为最新的XAML更新这个答案了。

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

在寻找这个问题的解决方案时,我发现更新后的XAML规范有一个简单的解决方案。

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

现在可以使用名为“占位符”的属性来完成此任务。就这么简单(在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>

#14


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;
            }           
    }
}

#15


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

需要一些代码,但是您可以将它用于任何组合框或文本框(甚至是密码框),所以我更喜欢这种方式

#16


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

我正在我的项目中使用一个IsNullConverter类,它对我很有用。这里是c#中的代码,创建一个名为Converter的文件夹,并在该文件夹中添加这个类,因为使用的触发器不支持value而不是null, IsNullConverter只支持这个操作

 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.

在xaml文件中添加命名空间如下所示。

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

使用参考资料下面的这一行代码通过xaml代码可用

<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.

这是xaml代码,我在这里使用了触发器,所以每当在combobox中选择一个项目时,文本的可见性就会变为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>

#17


0  

//XAML Code

/ / XAML代码

// 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");

        }
    }

#18


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.

一种更简单的方法是将一个假数据项添加到参数is哑=true的列表中,并确保它不是HitTestVisable,并且它的高度为1像素(使用转换器),因此不会被看到。

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

不只是注册到SelectionChanged中,将索引设置为哑项索引。

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

它的工作方式就像一种魅力,这样你就不会打乱ComboBox的风格和颜色,或者你的应用主题。

#19


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.

上面的代码演示了实现它的最简单方法。在窗口加载后,使用combobox的. text属性声明combobox的文本。这也可以扩展到DatePicker、Textbox和其他控件。

#20


0  

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

在将combobox与数据库中的数据绑定在一起之前,我这样做了。

Combobox.Items.Add("-- Select Team --");
Combobox.SelectedIndex = 0;

#21


-2  

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}" />

#22


-3  

Only set the IsEditable attribute to true

只将IsEditable属性设置为true

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