Search code examples
c#wpfxamlcombobox

Multiple SelectedValuePath/SelectedValue binding on ComboBox with List<Tuple<long, long, string>> ItemsSource


I have a ComboBox which has an ItemSource of List<Tuple<long, long, string>>. In the tuple Item3 is some user-friendly display text, Item1 and Item2 are two different (but 1-to-1 related) sequences/keys that I need to update on a bound object when the user changes the selected item.

I can bind one of these sequences easily enough like this:

<ComboBox ItemsSource="{Binding MyList, Mode=OneWay}"
          DisplayMemberPath="Item3"
          SelectedValuePath="Item1"
          SelectedValue="{Binding MyObject.FirstSequence, Mode=TwoWay}"

What I am trying to achieve is something like:

<ComboBox ItemsSource="{Binding MyList, Mode=OneWay}"
          DisplayMemberPath="Item3"
          SelectedValuePath1="Item1"
          SelectedValue1="{Binding MyObject.FirstSequence, Mode=TwoWay}"
          SelectedValuePath2="Item2"
          SelectedValue2="{Binding MyObject.SecondSequence, Mode=TwoWay}"

Is it possible to achieve something like this, perhaps with multibinding?

I have tried setting MyObject.SecondSequence in the setter of MyObject.FirstSequence however MyObject.FirstSequence and MyObject.SecondSequence are also populated from a database initially and I only need to update them both when the user makes a change, so this would add quite a bit of additional and unnecessary overhead in 99% of cases.

I could potentially change MyObject.FirstSequence and MyObject.SecondSequence to a class that holds both sequences something like this:

class Sequences
{
    string DisplayText { get; set; }
    long FirstSequence { get; set; }
    long SecondSequence { get; set; }
}

Then set ComboBox.ItemsSource to List<Sequences> and bind to MyObject.Sequences, however that would mean quite a lot of other code changes and I want to explore other options first.


Solution

  • The view model could have a SelectedTuple property that sets the properties of MyObject:

    private Tuple<long, long, string> selectedTuple;
    
    public Tuple<long, long, string> SelectedTuple
    {
        get => selectedTuple;
        set
        {
            selectedTuple = value;
            MyObject.FirstSequence = selectedTuple.Item1;
            MyObject.SecondSequence = selectedTuple.Item2;
            NotifyPropertyChanged(nameof(SelectedTuple));
        }
    }
    

    It would be set like shown below - initially, but perhaps also in a PropertyChanged event handler attached to MyObject.

    SelectedTuple = MyList.FirstOrDefault(t =>
        t.Item1 == MyObject.FirstSequence && t.Item2 == MyObject.SecondSequence);
    

    The SelectedTuple property would be bound to like this:

    <ComboBox ItemsSource="{Binding MyList}"
              SelectedItem="{Binding SelectedTuple}"
              DisplayMemberPath="Item3"/>