0

The Index and value are displayed in the DropDown, but only the value is displayed in the ComboBox. How can I display the Index even when the DropDown is closed?

<ComboBox ItemsSource="{Binding DoubleList}" AlternationCount="{x:Static system:Int32.MaxValue}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock>
                <Run Text="{Binding (ItemsControl.AlternationIndex), Mode=OneWay, RelativeSource={RelativeSource AncestorType=ComboBoxItem}, StringFormat={}{0} :"/>
                <Run Text="{Binding ., StringFormat={}{0:F4}}"/>
            </TextBlock>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>
test
  • 13
  • 4
  • Does this answer your question? [WPF Combobox: Different template in textbox and drop-downlist](https://stackoverflow.com/questions/3671986/wpf-combobox-different-template-in-textbox-and-drop-downlist) – Andrew KeepCoding Sep 07 '22 at 07:23
  • There's no itemscontrol at all when your combo is not expanded so anything relying on alternationindex is a bad choice. Just number your double list items when you create them. In a new property in your item viewmodel. Bind to that new property. – Andy Sep 07 '22 at 17:01

1 Answers1

0

There is no ComboBoxItem present in the visual tree when the ComboBox is closed so your current solution of binding to the ItemsControl.AlternationIndex attached property of a (non-existing) parent ComboBoxItem won't work.

You should change the type of your DoubleList from IEnumerable<double> to IEnumerable<T> where T is a view model with a property to store the index of the item:

public class Item : INotifyPropertyChanged
{
    private int _index;
    public int Index
    {
        get { return _index; }
        set { _index = value; NotifyPropertyChanged(); }
    }

    private double _value;
    public double Value
    {
        get { return _value; }
        set { _value = value; NotifyPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
...
public IEnumerable<Item> DoubleList { get; }

You will then have to set it one way or the other, for example using an event handler in the view:

private void ComboBoxItem_Loaded(object sender, RoutedEventArgs e)
{
    ComboBoxItem comboBoxItem = (ComboBoxItem)sender;
    Item item = comboBoxItem.DataContext as Item;
    if (item != null)
        item.Index = ItemsControl.GetAlternationIndex(comboBoxItem);
}

XAML::

<ComboBox ItemsSource="{Binding DoubleList}" AlternationCount="{x:Static system:Int32.MaxValue}">
    <ComboBox.ItemContainerStyle>
        <Style TargetType="ComboBoxItem">
            <EventSetter Event="Loaded" Handler="ComboBoxItem_Loaded" />
        </Style>
    </ComboBox.ItemContainerStyle>
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock>
                <Run Text="{Binding Index, Mode=OneWay, StringFormat={}{0} :}"/>
                <Run Text="{Binding Value, StringFormat={}{0:F4}}"/>
            </TextBlock>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

This is MVVM in a nutshell. The fact that the view sets a property of the view model programmatically is as fine as doing it through a binding in the XAML markup (which is not possible in this particular case).

mm8
  • 163,881
  • 10
  • 57
  • 88