Search code examples
c#wpfxamldata-bindingcombobox

How to fill a ComboBox with indexes of bound collection?


I want to create a ComboBox with contents of TextBlocks that are in the from "Sample 01", where the number is replaced with the index of the item (from 1).

Below is roughly my current code:

<ComboBox
    x:Name="ComboSampleItems"
    Grid.Column="0"
    Height="20"
    HorizontalAlignment="Stretch"
    ItemsSource="{Binding ReportModel.SampleData}"
    SelectedItem="{Binding SelectedSampleScans}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding ????, StringFormat=Something here?}" />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

I am using INPC to ensure that changes on the VM reflect the View, as I am using MVVM. How can I achieve my desired result? I have considered converters, but am not sure it fits in what I am wanting to do, or if there is a better way.

Does this at all relate to this topic?


Solution

  • Collections do not provide an explicit index for their items. In other words, although e.g. a List<string> contains strings and all of them can be indexed, there is no property for the index of an individual item. What you could do is simply expose a collection of (Index, Item) tuples. Note, I use Tuple<string, int> here, because value tuples like (string, int) are not bindable. You could also construct a custom type or use KeyValuePair<string, int> instead.

    public List<Tuple<string, int>> IndexedSampleData { get; }
    

    You can initialize it using LINQ and its Select method. Depending on your concrete case, you might as well use a IEnumerable<(string, int)> or an ObservableCollection<(string, int)> for this purpose.

    IndexedSampleData = SampleData.Select((item, index) => new Tuple<string, int>(item, index)).ToList();
    

    In XAML you can use a MultiBinding in combination with StringFormat, see Standard numeric format strings. Refer to the tuple components using the properties Item1 and Item2.

    <ComboBox
       x:Name="ComboSampleItems"
       Grid.Column="0"
       Height="20"
       HorizontalAlignment="Stretch"
       ItemsSource="{Binding IndexedSampleData}">
       <ComboBox.ItemTemplate>
          <DataTemplate>
             <TextBlock>
                <TextBlock.Text>
                   <MultiBinding StringFormat="{}{0} {1:D2}">
                      <Binding Path="Item1"/>
                      <Binding Path="Item2"/>
                   </MultiBinding>
                </TextBlock.Text>
             </TextBlock>
          </DataTemplate>
       </ComboBox.ItemTemplate>
    </ComboBox>
    

    ComboBox with sample data.