如何在WPF页面加载的组合框中显示默认文本“ --Select Team-”?


109

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

“-选择团队-”

以便在页面加载时显示它,并在选择它时清除文本并显示项目。

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

请指导我

Answers:


107

我发现最简单的方法是:

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

您显然需要添加其他选项,但这可能是最简单的方法。

但是,此方法有一个缺点,即组合框内的文本不可编辑,但仍可以选择。但是,鉴于我迄今为止发现的每个替代方案的质量和复杂性较差,这可能是最好的选择。


克里斯,好答案!我只添加Focusable =“ True”,但这只是表面上的变化。
Slavisa

6
克里斯的完美答案。一个物业可以发挥如此大的作用:D
Aster Veigas 2013年

4
Focusable="False" IsEditable="True" IsReadOnly="True"
Kamil Lelonek 2014年

1
+1。不幸的是,它不适用于混合项目(例如,如果组合框项目是图像)。
greenoldman 2014年

11
简单有效的解决方案。WPF控件在整个框架中都存在此类问题。在各处,控件缺少大多数开发人员所需的功能。结果,开发人员浪费了时间寻找解决方案,购买第三方替代控件或实施变通方法。WPF团队是否甚至将控件用于自己的开发?
该死的蔬菜

90

您可以使用来完成此操作,而不会留下任何代码IValueConverter

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

在这里,您可以重新使用转换器类。

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
}

最后,您需要在资源部分中声明转换器。

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

转换器是您放置转换器类的地方。一个例子是:

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

这种方法的优点是在您的代码后面没有重复代码。


我想使用它,但是似乎在组合框是datagrid的标头的情况下是不允许的。。。XAML给出一个错误,指出已经定义了标头(或者不能多次定义标头)。有任何想法吗?我在考虑只使用null值选项,然后可以通过选择它来进行重置,但似乎有些草率。
Paul Gibson

1
这是一个出色的解决方案的一个重要原因是,几乎每个数据绑定的WPF项目都使用了NullToVisibilityConverter,因此大多数时间它都已经存在-最好使用它!
tpartee

2
实际上,您DataTrigger甚至可以在这里使用a 来避免转换器代码:)
Billy ONeal

49

我喜欢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>

33

没有人说过纯xaml解决方案必须很复杂。这是一个简单的示例,在文本框上有1个数据触发器。所需的保证金和头寸

<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
我需要移动“能见度=”隐藏”到数据触发,然后它的工作如预期无疑是最straigh前进的方法,我已经看到了可重用性,我感动的风格融入了资源。
米奇

@Mitch IceForce的答案对我不起作用,为了使它起作用,您进行了哪些更改?
克里斯(Chris)

1
@Chris我认为他的意思是<Setter Property="Visibility" Value="Hidden"/>在触发器之外(在样式内)并Visibility="Hidden"从实际的textblock元素中删除
恢复Monica请

@Mitch,如果DataTrigger中的ElementName指向特定对象(mybox),如何将Textblock样式移到资源中以供重用?有什么方法可以以通用方式指定该名称?
CrApHeR


16

我不知道它是否直接受支持,但是如果选择不为null,则可以用标签覆盖该组合并将其设置为隐藏。

例如。

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

然后在选择中更改处理程序...

private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    txtSelectTeam.Visibility = comboBox1.SelectedItem == null ? Visibility.Visible : Visibility.Hidden;
}

1
可以使用XAML来设置TextBlock的可见性,而不是使用SelectionChanged处理程序。
aliceraunsbaek

6

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

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>

使用示例:

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

真好 我已经通过使用相对源绑定TextBlock的DataContext来消除它,以避免必须设置名称。请参阅Markup的下一条注释(SO注释中的代码看起来很难看)
Sascha

<TextBlock DataContext =“ {绑定路径=儿童[0] .SelectedItem,RelativeSource = {RelativeSource AncestorType = Grid}}”“ Text =”-选择项目-“ Style =” {StaticResource ComboBoxSelectOverlay}“ />
Sascha

4

没有尝试使用组合框,但是这对我来说与其他控件一起工作...

ageektrapped博客文章

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


刚刚下载并尝试了此代码。它似乎按广告样工作。允许您使用包含水印的简单附加属性装饰组合。它也适用于其他控件。这是比该问题的任何其他答案都更好的方法。
伊恩·奥克斯

好东西,不仅解决了ComboBox问题,而且现在我可以摆脱WPF Tools程序集,而直接在TextBoxes上使用它而不是WatermarkedTextBox控件,所以充满了胜利:)-哦,顺便说一句,它不是A Geek Trapped约定陷阱!
dain 2012年

2

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>

2

最简单的方法是使用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>

并且在“资源”中定义StaticResource以将ComboBox选项绑定到您的DataContext,因为CollectionContainer中的直接绑定无法正常工作。

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

这样,您只能在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>

1

我建议以下内容:

定义行为

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

用户行为

<ComboBox Name="cmb" Margin="72,121,0,0" VerticalAlignment="Top"
          local:ComboBoxBehaviors.DefaultText="-- Select Team --"/>

这就像单个组合框的魅力一样。但是,当我将其与1个以上的组合一起使用时,它给我一个错误(但编译并运行良好)“'DefaultText'属性已由'ComboBox'注册”。我在博客中提到了此修复程序。
Romesh D. Niriella 2014年

感谢您指出了这一点。我无法在计算机上产生此错误。但是,我同意typeof(ComboBoxBehaviors)应该在RegisterAttached的第3个参数中传递,而不是typeof(ComboBox)。
Usman Zafar 2014年

尽管这篇文章有些陈旧,但我不知道它如何工作。通过带有多种条件的触发器设置组合的背景色。尝试将单独的组合放置在网格上,然后将bg手动设置为“红色”。它对要显示水印的区域没有影响。它可能只会影响下拉面板后面的背景色。更好的解决方案是复制组合框的控件模板,并添加一些触发器和样式,以将由文本块组成的可视画笔绘制到边框的背景中。
Newclique

1

IceForge的答案非常接近,并且AFAIK是此问题的最简单解决方案。但是它错过了一些东西,因为它不起作用(至少对我来说,它从未真正显示过文字)。

最后,您不能仅将TextBlock的“ Visibility”属性设置为“ Hidden”,以便在组合框的选定项不为null时将其隐藏。您必须在默认情况下以这种方式进行设置(因为您无法在触发器中检查是否不为null在XAML中与触发器相同的位置使用Setter。

这是基于他的实际解决方案,将丢失的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>

1

编辑:根据下面的评论,这不是解决方案。不确定我的工作方式,无法检查该项目。

现在该更新该答案以获取最新的XAML。

找到这个SO问题以寻找该问题的解决方案,然后我发现更新的XAML规范具有一个简单的解决方案。

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

我使用了此解决方案-否决选民会在意吗?当然,我不是XAML专家,但它确实有效。
罗伯·萨德勒

1
尽管我不是反对派选民,但我认为您被否决了,因为班上没有PlaceholderText财产。这是有关WPF而不是WinForms的问题。System.Windows.ComboBox
谢里登

伙计,这很奇怪-我知道我在使用XAML应用程序,而且我知道我刚刚发现它并看到它可以工作。也许扩展包含在项目中?IDK-从那以后,我确定ComboBox中没有占位符。我无法回到我正在从事的项目-老客户。啊。
Robb Sadler '18

2
您没有错,但这不是WPF的问题。UWP ComboBox具有此功能,请参见以下页面:msdn.microsoft.com/en-us/library/windows/apps/…–
laishiekai

0

不是最佳做法。但是效果很好...

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

后面的代码

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

0

我相信这篇文章中提到的水印在这种情况下会很好用

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


0

我在项目中使用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.");
    }
}

像这样在xaml文件中添加名称空间。

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

手段

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

在资源下方使用此行,以通过xaml代码使用该行

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

这是xaml代码,我在这里使用了触发器,因此,只要在组合框中选择了一个项目,文本的可见性就会变为假。

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

0

// XAML代码

// ViewModel代码

    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

有点晚了..

一种更简单的方法是使用参数IsDummy = true将虚拟数据项添加到列表中,并确保它不是HitTestVisable,并且其高是1像素(使用Converter),这样它就不会被看到。

不仅要注册到SelectionChanged,而且还要在其中将索引设置为虚拟商品索引。

它像一种魅力一样工作,这样您就不会混淆ComboBox的样式和颜色或您的应用程序主题。


0
InitializeComponent()
yourcombobox.text=" -- Select Team --";

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


0

我在将组合框与来自代码隐藏的数据库中的数据绑定在一起之前就做到了-

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

1
这只是将文本添加为​​下拉菜单中的一个选项。那不是OP所要求的。
迪恩·弗里德兰德

这是关于添加默认文本的,我是用这种方式做到的
Atiq Baqi

0
  1. 在组合框的顶部放置一个标签。

  2. 将标签的内容绑定到组合框的Text属性。

  3. 将组合框的不透明度设置为零,不透明度= 0。

  4. 在组合框的Text属性中写入默认文本

          <ComboBox Name="cb"
            Text="--Select Team--" Opacity="0" 
            Height="40" Width="140" >
             <ComboBoxItem Content="Manchester United" />
             <ComboBoxItem Content="Lester" />
         </ComboBox>
     </Grid>

-2

仅将IsEditable属性设置为true

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

-3

我知道这是半旧的,但是这种方式呢:

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

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

2
ComboBox没有EmptySelectionBoxTemplate财产。
Novitchi S 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.