llenar - Cómo mostrar el texto predeterminado "--Seleccione Team-" en el cuadro combinado en la carga de la página en WPF?




wpf fill combobox from list (15)

// Código XAML

// Código de 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");

        }
    }

En una aplicación WPF, en la aplicación MVP, tengo un cuadro combinado, para el cual visualizo los datos obtenidos de la base de datos. Antes de los elementos agregados al cuadro Combo, quiero mostrar el texto predeterminado como

" -- Selecciona un equipo --"

para que en la carga de página se muestre y al seleccionarlo, el texto se borre y los elementos se muestren.

Seleccionar datos de DB está sucediendo. Necesito mostrar el texto predeterminado hasta que el usuario seleccione un elemento del cuadro combinado.

Por favor guíame


Basado en la respuesta de IceForge, preparé una solución reutilizable:

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

ejemplo de uso:

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

EDITAR: según los comentarios a continuación, esta no es una solución. No estoy seguro de cómo lo estaba trabajando, y no puedo verificar ese proyecto.

Es hora de actualizar esta respuesta para el último XAML.

Al encontrar esta pregunta SO para encontrar una solución a esta pregunta, descubrí que la especificación XAML actualizada tiene una solución simple.

Un atributo llamado "Placeholder" ahora está disponible para realizar esta tarea. Es tan simple como esto (en 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>

Establecer IsEditable = True en el elemento Combobox. Esto mostrará la propiedad Text del Combobox


La forma más fácil que he encontrado para hacer esto es:

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

Obviamente tendrá que agregar sus otras opciones, pero esta es probablemente la forma más sencilla de hacerlo.

Sin embargo, hay un inconveniente en este método, que es cuando el texto dentro de su cuadro combinado no será editable, todavía es seleccionable. Sin embargo, dada la baja calidad y complejidad de cada alternativa que he encontrado hasta la fecha, esta es probablemente la mejor opción.


La forma más sencilla es utilizar CompositeCollection para fusionar texto y datos predeterminados de la base de datos directamente en ComboBox, por ejemplo:

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

Y en Resources define StaticResource para vincular las opciones de ComboBox a su DataContext, porque el enlace directo en CollectionContainer no funciona correctamente.

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

De esta forma, puede definir sus opciones de ComboBox solo en xaml, por ejemplo

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

Lo hice antes de vincular el combobox con los datos de la base de datos en código detrás de este modo:

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

Me gusta la respuesta de Tri Q, pero esos convertidores de valor son difíciles de usar. PaulB lo hizo con un controlador de eventos, pero eso también es innecesario. Aquí hay una solución XAML pura:

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

No es una buena práctica ... pero funciona bien ...

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

Código detrás

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

No lo intenté con cuadros combinados pero esto me ha funcionado con otros controles ...

blogpost ageektrapped

Él usa la capa adorner aquí para mostrar una marca de agua.


Sé que esto es semi viejo, pero ¿qué tal de esta manera?

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

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

Solo establece el atributo IsEditable en true

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

Yo recomendaría lo siguiente:

Definir un comportamiento

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

Usuario el comportamiento

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

La respuesta de IceForge fue bastante cercana, y es AFAIK la solución más fácil para este problema. Pero falló algo, ya que no funcionaba (al menos para mí, nunca muestra el texto).

Al final, no puede simplemente establecer la propiedad "Visibilidad" de TextBlock en "Oculto" para que se oculte cuando el elemento seleccionado del cuadro combinado no sea nulo; tienes que CONFIGURARLO de esa manera por defecto (ya que no puedes verificar nulo en disparadores , usando un Setter en XAML en el mismo lugar que los Triggers).

Aquí está la solución real basada en la suya, el Setter faltante se coloca justo antes de los desencadenantes:

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

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

El código anterior muestra la forma más sencilla de lograrlo. Después de la carga de la ventana, declare el texto del cuadro combinado, utilizando la propiedad .Text del cuadro combinado. Esto también se puede extender al DatePicker, Textbox y otros controles.