XAML > Binding SelectedValue to a concatenation of 2 properties

JM Deb 1 Reputation point
2020-04-12T08:04:22.117+00:00

Hi,

I've a Person class

public class Person
{
    public string location;
    public string name;
    ...
}

...and a list of Person

List<Person> list1 = new List<Person>()
{
    new Person() { location = "Chicago", name = "Michael" },
    new Person() { location = "", name = "Mario" },
    new Person() { location = "Denver", name = "Michael" }
};

In a ComboBox, I want to display this list formated that way: name (location). So I've used a Converter and it's working fine until there:

<ComboBox ItemsSource="{Binding list1}" IsSynchronizedWithCurrentItem="True">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Converter={StaticResource concatNameAndLoc}}"/>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

Public Class ConcatNameAndOption
    Implements IValueConverter
    Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
        Dim valConv As Person = TryCast(value, Person)

        Dim loc As String = valConv.Location
        If loc <> "" Then
            loc = " (" & loc & ")"
        End If

        Return valConv.Name & loc
    End Function
    Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
        Return value
    End Function
End Class

I can see the data displayed correctly in my ComboBox:
Michael (Chicago)
Mario
Michael (Denver)

Now, here is my problem:
The selected Person will be saved in a XML file (<Person location="Paris">Michel</Person>) and I would like, at loading, that the ComboBox selects this Person (the one with the matching Name and Location concatenation)
...in other words, from the concatenation on the 'saved' person, I want to find the corresponding concatenated person in the list.

How to bind the SelectedValue? I've tryed SelectedValue="{Binding Person, Converter={StaticResource concatNameAndOpt}, NotifyOnSourceUpdated=True}"
...but without succes.

Thanks for reading me! Hope that I was clear!

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,671 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2020-04-12T09:15:55.863+00:00

    Hi, find the person in list1 und set selected value. Try following demo:

    XAML:

    <Window x:Class="WpfApp1.Window27"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp27"
            mc:Ignorable="d"
            Title="Window27" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <Window.Resources>
        <local:ConcatNameAndOption x:Key="concatNameAndLoc"/>
      </Window.Resources>
      <StackPanel>
        <ComboBox ItemsSource="{Binding View}" 
                  SelectedValue="{Binding SelectedPerson}">
          <ComboBox.ItemTemplate>
            <DataTemplate>
              <TextBlock Text="{Binding Converter={StaticResource concatNameAndLoc}}"/>
            </DataTemplate>
          </ComboBox.ItemTemplate>
        </ComboBox>
      </StackPanel>
    </Window>
    

    And classes:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfApp27
    {
      public class ViewModel
      {
        public ViewModel()
        {
          cvs.Source = list1;
    
          // set selected value
          SelectedPerson = list1.Find((p) =>
          {
            return p.Location == "Paris" && p.Name == "Michael";
          });
        }
    
        public List<Person> list1 = new List<Person>()
         {
             new Person() { Location = "Chicago", Name = "Michael" },
             new Person() { Location = "", Name = "Mario" },
             new Person() { Location = "Paris", Name = "Michael" },
             new Person() { Location = "Denver", Name = "Michael" }
         };
    
        CollectionViewSource cvs = new CollectionViewSource();
        public ICollectionView View { get => cvs.View; }
    
        public Person SelectedPerson { get; set; }
      }
      public class Person
      {
        public string Location { get; set; }
        public string Name { get; set; }
      }
      public class ConcatNameAndOption : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
          Person valConv = value as Person;
          string loc = valConv.Location;
          if (loc != "") loc = " (" + loc + ")";
          return valConv.Name + loc;
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => value;
      }
    }
    
    0 comments No comments