Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combobox binding itemsource to custom list and selecteditem to an instance of that list doesn't work

I tried really different ways to make my combobox working but I'm still stuck :(

Here is a very simplified version of my app : (just edited, sorry for mistakes)

<ListView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson}"/>
<ComboBox ItemsSource="{Binding Grades}" SelectedItem="{Binding SelectedPerson.MyGrade}" 
     DisplayMemberPath="Name"/>

And the code behind :

public class Person
{
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            if (name != value)
            {
                name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }

    private Grade myGrade;
    public Grade MyGrade
    {
        get { return myGrade; }
        set
        {
            if (myGrade != value)
            {
                myGrade = value;
                NotifyPropertyChanged("MyGrade");
            }
        }

    }

    //-- INotifyPropertyChanged implementation
}
public class Grade
{
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            if (name != value)
            {
                name = value;
                NotifyPropertyChanged("Name");
            }
        }
    }

    private int prop;
    public int Prop
    {
        get { return prop; }
        set
        {
            if (prop != value)
            {
                prop = value;
                NotifyPropertyChanged("Prop");
            }
        }

    }

    //-- INotifyPropertyChanged implementation
}
public partial class MainWindow : Window
{
    public ObservableCollection<Person> People { get; set; }
    public ObservableCollection<Grade> Grades { get; set; }

    private Person selectedPerson;
    public Person SelectedPerson
    {
        get { return selectedPerson; }
        set
        {
            if (selectedPerson != value)
            {
                selectedPerson = value;
                NotifyPropertyChanged("SelectedPerson");
            }
        }
    }

    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = this;

        People = new ObservableCollection<Person>();
        Grades = new ObservableCollection<Grade>();

        Grades.Add(new Grade() { Name = "Grade 1", Prop = 1 });
        Grades.Add(new Grade() { Name = "Grade 2", Prop = 2 });

        People.Add(new Person() { Name = "guy 1", MyGrade = Grades[0] });
        People.Add(new Person() { Name = "guy 2", MyGrade = Grades[0] });
        People.Add(new Person() { Name = "guy 3", MyGrade = Grades[1] });
    }

    //-- INotifyPropertyChanged implementation
}

The problem is that the combobox is still empty when I select an item in the listview. The itemsource is OK (If I click on the combobox, I can see "grade 1" and "grade 2"). I think there is something missing to tell "the Person.Grade is part of the Grades list" but I cannot find what.

Hope you can help me ;)

like image 568
anthoLB29 Avatar asked Dec 17 '13 22:12

anthoLB29


1 Answers

Is the SelectedItem the exact same reference in memory as the item in the ItemsSource?

By default, WPF will compare the SelectedItem to the items in the ItemsSource by reference, and if they're not the same reference in memory, it will return no matching item.

If you are unable to do this in your code, the most common workarounds are to either:

  • Bind the SelectedValue to a value type instead of a reference type, and set the SelectedValuePath

    <ComboBox ItemsSource="{Binding Grades}" 
              SelectedValue="{Binding SelectedPerson.MyGrade.GradeId}" 
              SelectedValuePath="GradeId"
              DisplayMemberPath="Name"/>
    
  • Or override the .Equals() to ensure the two objects are considered equal when specific properties match, as opposed to being considered equal when the reference in memory matches.

    public override bool Equals(object obj) 
    { 
        if (obj == null || !(obj is Grade)) 
            return false; 
    
        return ((Grade)obj).GradeId == this.GradeId); 
    }
    
like image 82
Rachel Avatar answered Sep 27 '22 19:09

Rachel