1

I'm working on a few ComboBoxes that need a "select" property as the top option in WPF (c#)

At the moment I have the combobox's named and then populated in the code behind from a array string.

<ComboBox Width="150" x:Name="cmbTitle" Margin="3" SelectedIndex="0" /> 

.

cmbTitle.Items.Add("Select"); foreach (var title in Constants.Title) cmbTitle.Items.Add(title); 

My Issue is that the selectd Index will always be off by 1 of the index in the string.

After doing my research I see that this is a very prehistoric way of populating a combo box (WinFrom background). Constants seem to be stored in Enums in every example I have looked at so would like to move away from multiple string[]s.

What is my best way of binding an enum to a combobox while accommodating for a "select" option in WPF? I've looked at half a dozen options today and I'm not too sure what other code examples to list.

It's quite a open question, but I'm quite lost.

Thanks in advance, Oli

2
  • 1
    Should the "Select" option be available for picking, or it's just a prompt for users? If latter, there's a better way of doing that. Commented Jan 19, 2012 at 15:37
  • @Joulukuusi It should just be a prompt for the user. Thanks, this looks very useful. Commented Jan 19, 2012 at 15:57

2 Answers 2

1
  1. Values of an enumeration can be retrieved from Enum.GetValues(), and binding to a method is typically done using ObjectDataProvider. Here's an example of getting all BindingMode values:

    <ObjectDataProvider x:Key="BindingModes" ObjectType="{x:Type sys:Enum}" MethodName="GetValues"> <ObjectDataProvider.MethodParameters> <x:Type TypeName="BindingMode" /> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> 

    Now, we can bind ItemsSource of our ComboBox:

    <ComboBox ItemsSource="{Binding Source={StaticResource BindingModes}}" /> 
  2. Our control needs a new property for the prompt:

    public class ExtendedComboBox : ComboBox { public static readonly DependencyProperty PromptProperty = DependencyProperty.Register("Prompt", typeof(string), typeof(ExtendedComboBox), new PropertyMetadata(string.Empty)); public string Prompt { get { return (string)GetValue(PromptTextProperty); } set { SetValue(PromptTextProperty, value); } } } 

    We can cheat a bit and place a TextBlock with the prompt inside our control, and hide it when there's an item selected. For this we rewrite ControlTemplate of the control with a new one containing the TextBlock. I modified template from there:

    <Style x:Key="PromptTextBlock" TargetType="{x:Type TextBlock}" > <Setter Property="Visibility" Value="Hidden" /> <Style.Triggers> <DataTrigger Binding="{Binding SelectedItem, RelativeSource={RelativeSource TemplatedParent}}" Value="{x:Null}"> <Setter Property="Visibility" Value="Visible" /> </DataTrigger> </Style.Triggers> </Style> <Style x:Key="PromptedComboBox" TargetType="{x:Type local:ExtendedComboBox}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:ExtendedComboBox}"> <Grid> <ToggleButton x:Name="DropDownToggle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="-1" HorizontalContentAlignment="Right" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"> <Path x:Name="BtnArrow" Height="4" Width="8" Stretch="Uniform" Margin="0,0,4,0" Fill="Black" Data="F1 M 300,-190L 310,-190L 305,-183L 301,-190 Z " /> </ToggleButton> <ContentPresenter x:Name="ContentPresenter" Margin="6,2,25,2" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"> </ContentPresenter> <TextBox x:Name="PART_EditableTextBox" Style="{x:Null}" Focusable="False" Background="{TemplateBinding Background}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,3,23,3" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}"/> <Popup x:Name="PART_Popup" IsOpen="{TemplateBinding IsDropDownOpen}"> <Border x:Name="PopupBorder" HorizontalAlignment="Stretch" Height="Auto" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="Black" Background="White" CornerRadius="3"> <ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1"> <ItemsPresenter/> </ScrollViewer> </Border> </Popup> <TextBlock Margin="4,3,20,3" Text="{Binding PromptText, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource PromptTextBlock}"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> 
  3. Combining, we have:

    <local:ExtendedComboBox Style="{StaticResource PromptedComboBox}" Prompt="Select an item" ItemsSource="{Binding Source={StaticResource BindingModes}}" /> 
Sign up to request clarification or add additional context in comments.

Comments

1

I think the best way to populate your ComboBox will be using IDictionary.

As an example, your code-behind:

public YourEnum SelectedOption { get; set; } public IDictionary<string, YourEnum> Options = new Dictionary<string, YourEnum?>(); Options.Add("Select", null); Options.Add("Option 1", YourEnum.Option1); ... Options.Add("Option N", YourEnum.OptionN); 

Your xaml file:

<ComboBox ItemsSource="{Binding Options, ...}" SelectedValue="{Binding SelectedOption, ...}" DisplayMemberPath="Key" SelectedValuePath="Value" /> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.