如何显示WPF页面加载combobox中的默认文本“ – select团队 – ”?
在MVP应用程序中,我有一个combobox,为此我显示从数据库中获取的数据。 在项目添加到combobox之前,我想显示默认的文本,如
“ – select团队 – ”
所以在页面载入时显示,select它应该清除文本,并显示项目。
从数据库中select数据正在发生。 我需要显示默认的文本,直到用户从combobox中select一个项目。
请指导我
你可以通过使用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"
这种方法的好处是在你的代码中没有重复的代码。
我发现最简单的方法是:
<ComboBox Name="MyComboBox" IsEditable="True" IsReadOnly="True" Text="-- Select Team --" />
您显然需要添加其他选项,但这可能是最简单的方法。
然而,这种方法有一个缺点,那就是combobox中的文本不可编辑,它仍然是可选的。 但是,鉴于迄今为止我发现的每一个替代品的质量和复杂性都很差,这可能是最好的select。
我喜欢Tri Q的答案,但这些价值转换器是一个痛苦的使用。 PaulB做了一个事件处理程序,但这也是不必要的。 这是一个纯粹的XAML解决scheme:
<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>
没有人说纯粹的xaml解决scheme必须是复杂的。 这是一个简单的,在文本框中有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>
在Combobox元素上设置IsEditable = True。 这将显示Combobox的Text属性
我不知道它是否直接支持,但你可以覆盖组合与标签,并将其设置为隐藏,如果select不为空。
例如。
<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>
然后在select更改处理程序…
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e) { txtSelectTeam.Visibility = comboBox1.SelectedItem == null ? Visibility.Visible : Visibility.Hidden; }
没有用combobox尝试过,但这已经为我工作与其他控制…
年龄限制的博客post
他在这里使用装饰层来显示水印。
基于IceForge的回答,我准备了一个可重复使用的解决scheme:
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>
HappyNomad的解决scheme非常好,最终帮助我达到了这个略有不同的解决scheme。
<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>
最简单的方法是使用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>
我会build议如下:
定义一个行为
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 --"/>
IceForge的答案非常接近,而AFAIK是解决这个问题的最简单的解决scheme。 但它错过了一些东西,因为它不起作用(至less对我来说,它从来没有实际显示文本)。
最后,当combobox的select项不为空时,不能将TextBlock的“可见性”属性设置为“隐藏”,以便隐藏它。 你必须在默认情况下设置它(因为你不能在触发器中使用XAML中的Setter来检查触发器中是否为null 。
这是基于他的实际解决scheme,缺less的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>
不是最好的做法..但工作正常…
<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; } } }
我相信这篇文章中提到的水印在这种情况下可以很好地工作
有一些需要的代码,但你可以重用它的任何combobox或文本框(甚至密码箱),所以我更喜欢这种方式
我在我的项目中使用IsNullConverter类,它为我工作。 这里是它在C#中的代码,创build一个名为转换器的文件夹,并在该文件夹中添加此类,因为使用的触发器不支持值而不是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代码,我在这里使用了触发器,所以无论何时在combobox中select一个项目,您的文本的可见性就变成了错误。
<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>
// 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"); } }
有点晚了,但..
更简单的方法是用参数IsDummy = true向列表中添加一个虚拟数据项,并确保它不是HitTestVisable,它的高度是1像素(使用Converter),所以不会被看到。
除了注册到SelectionChanged并在其中,将索引设置为虚拟物品索引。
它就像一个魅力,这样你就不会混淆combobox或你的应用程序主题的风格和颜色。
InitializeComponent() yourcombobox.text=" -- Select Team --";
上面的代码演示了实现它的最简单的方法。 窗口加载后,使用combobox的.Text属性声明combobox的文本。 这可以扩展到DatePicker,Textbox和其他控件。
现在是更新最新XAML的答案的时候了。
find这个问题寻找解决这个问题,然后我发现更新的XAML规范有一个简单的解决scheme。
现在可以使用一个名为“Placeholder”的属性来完成这个任务。 这很简单(在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>
我知道这是半老,但这样呢:
<DataTemplate x:Key="italComboWM"> <TextBlock FontSize="11" FontFamily="Segoe UI" FontStyle="Italic" Text="--Select an item--" /> </DataTemplate> <ComboBox EmptySelectionBoxTemplate="{StaticResource italComboWM}" />
只能将IsEditable属性设置为true
<ComboBox Name="comboBox1" Text="--Select Team--" IsEditable="true" <---- that's all! IsReadOnly="true"/>