-1

I have a ListBox:

<ListBox   
    ItemsSource="{Binding SupplyGroups}" 
    SelectedItem="{Binding ModelSupplyGroup, Mode=TwoWay}"/>

SupplyGroups is an ObservableCollection<SupplyGroup>

SupplyGroup is an object with an int SupplyGroupId and a string SupplyGroupTitle. There is a public override string ToString() so the ListBox gets the Title for display.

ModelSupplyGroup is a Property that accesses the Model's SupplyGroup.

When the window loads up, the value saved as ModelSupplyGroup does not cause the matching ListBox row to be selected. If I modify the code so SupplyGroup object is replaced with a string, it works correctly. The binding appears to work in the opposite direction, so if a ListBox row is selected, it will update the bound ModelSupplyGroup correctly. Inspecting the Objects in the matching SupplyGroup in the ObervableCollection and ModelSupplyGroup, they have identical values for ID and Title.

public SupplyGroup ModelSupplyGroup
{
    get
    {
        return this.purchasingRepository.GetSupplyGroupById(this.Model.SupplyGroupId);
    }
    set
    {
        this.Model.SupplyGroup = value;
    }
}

The GetSupplyGroupById() returns the full object from the Id.

Steve Hall
  • 17
  • 6
  • 1
    You do not need to (and usually will not) override the ToString method. Instead, just set the ListBox's DisplayMemberPath property to select a SupplyGroup that is to be shown by the ListBox. If the visual appearacne is more than just showing a single property value, declare an appropriate DataTemplate as the ListBox's ItemTemplate. See [Data Templating Overview](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/data/data-templating-overview?view=netframeworkdesktop-4.8) for details. – Clemens Feb 20 '22 at 12:21
  • 1
    In order to select an item by its ID, set `SelectedValuePath="ID"` and bind `SelectedValue="{Binding SupplyGroupId}"` or whatever is an appropriate vuiew model property. Also note that the SelectedIndex, SelectedItem and SelectedValue properties bind TwoWay by default. You do not need to set Mode=TwoWay explicitly. – Clemens Feb 20 '22 at 12:23
  • 1
    Your actual problem might be that the GetSupplyGroupById method does not return a SupplyGroup instance that is contained in the SupplyGroups collection (but rather a new one). Better use the SelectedValue/Path approach in that case – Clemens Feb 20 '22 at 12:27
  • In addition to @Clemens comments, did you read the "related" SO link https://stackoverflow.com/questions/561166/binding-a-wpf-combobox-to-a-custom-list?rq=1 – Stefan Wuebbe Feb 20 '22 at 12:30

1 Answers1

0

The view model property to which the SelectedItem property of a ListBox is bound must return an object that compares equal to an element of the collection to which the ItemsSource property is bound.

If the item class does not override the Equals() method, equality means referential equality, which means that the view model property must return an object reference that is contained in the source collection.

The method

purchasingRepository.GetSupplyGroupById(this.Model.SupplyGroupId);

created an object with matching properties, but a different instance, i.e. one that was not contained in the SupplyGroups collection.

Modifying the property fixed the problem:

get
{
    foreach (var item in SupplyGroups)
    {
        if (item.SupplyGroupId == this.Model.SupplyGroupId)
        {
            return item;
        }
    }
    return null;
}

This could also be written using LINQ like

get
{
    return SupplyGroups.FirstOrDefault(
        sg => sg.SupplyGroupId == Model.SupplyGroupId);
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
Steve Hall
  • 17
  • 6